33 changes: 25 additions & 8 deletions clang-tools-extra/clang-tidy/google/ExplicitConstructorCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,10 @@ static bool isStdInitializerList(QualType Type) {
}

void ExplicitConstructorCheck::check(const MatchFinder::MatchResult &Result) {
constexpr char WarningMessage[] =
constexpr char NoExpressionWarningMessage[] =
"%0 must be marked explicit to avoid unintentional implicit conversions";
constexpr char WithExpressionWarningMessage[] =
"%0 explicit expression evaluates to 'false'";

if (const auto *Conversion =
Result.Nodes.getNodeAs<CXXConversionDecl>("conversion")) {
Expand All @@ -91,7 +93,7 @@ void ExplicitConstructorCheck::check(const MatchFinder::MatchResult &Result) {
// gmock to define matchers).
if (Loc.isMacroID())
return;
diag(Loc, WarningMessage)
diag(Loc, NoExpressionWarningMessage)
<< Conversion << FixItHint::CreateInsertion(Loc, "explicit ");
return;
}
Expand All @@ -101,9 +103,11 @@ void ExplicitConstructorCheck::check(const MatchFinder::MatchResult &Result) {
Ctor->getMinRequiredArguments() > 1)
return;

const ExplicitSpecifier ExplicitSpec = Ctor->getExplicitSpecifier();

bool TakesInitializerList = isStdInitializerList(
Ctor->getParamDecl(0)->getType().getNonReferenceType());
if (Ctor->isExplicit() &&
if (ExplicitSpec.isExplicit() &&
(Ctor->isCopyOrMoveConstructor() || TakesInitializerList)) {
auto IsKwExplicit = [](const Token &Tok) {
return Tok.is(tok::raw_identifier) &&
Expand All @@ -130,18 +134,31 @@ void ExplicitConstructorCheck::check(const MatchFinder::MatchResult &Result) {
return;
}

if (Ctor->isExplicit() || Ctor->isCopyOrMoveConstructor() ||
if (ExplicitSpec.isExplicit() || Ctor->isCopyOrMoveConstructor() ||
TakesInitializerList)
return;

bool SingleArgument =
// Don't complain about explicit(false) or dependent expressions
const Expr *ExplicitExpr = ExplicitSpec.getExpr();
if (ExplicitExpr) {
ExplicitExpr = ExplicitExpr->IgnoreImplicit();
if (isa<CXXBoolLiteralExpr>(ExplicitExpr) ||
ExplicitExpr->isInstantiationDependent())
return;
}

const bool SingleArgument =
Ctor->getNumParams() == 1 && !Ctor->getParamDecl(0)->isParameterPack();
SourceLocation Loc = Ctor->getLocation();
diag(Loc, WarningMessage)
auto Diag =
diag(Loc, ExplicitExpr ? WithExpressionWarningMessage
: NoExpressionWarningMessage)
<< (SingleArgument
? "single-argument constructors"
: "constructors that are callable with a single argument")
<< FixItHint::CreateInsertion(Loc, "explicit ");
: "constructors that are callable with a single argument");

if (!ExplicitExpr)
Diag << FixItHint::CreateInsertion(Loc, "explicit ");
}

} // namespace clang::tidy::google
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ namespace clang::tidy::hicpp {
IgnoredRemoveResultCheck::IgnoredRemoveResultCheck(llvm::StringRef Name,
ClangTidyContext *Context)
: UnusedReturnValueCheck(Name, Context,
"::std::remove;"
"::std::remove_if;"
"::std::unique") {
{
"::std::remove",
"::std::remove_if",
"::std::unique",
}) {
// The constructor for ClangTidyCheck needs to have been called
// before we can access options via Options.get().
AllowCastToVoid = Options.get("AllowCastToVoid", true);
Expand Down
170 changes: 138 additions & 32 deletions clang-tools-extra/clangd/HeuristicResolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,80 @@
namespace clang {
namespace clangd {

namespace {

// Helper class for implementing HeuristicResolver.
// Unlike HeuristicResolver which is a long-lived class,
// a new instance of this class is created for every external
// call into a HeuristicResolver operation. That allows this
// class to store state that's local to such a top-level call,
// particularly "recursion protection sets" that keep track of
// nodes that have already been seen to avoid infinite recursion.
class HeuristicResolverImpl {
public:
HeuristicResolverImpl(ASTContext &Ctx) : Ctx(Ctx) {}

// These functions match the public interface of HeuristicResolver
// (but aren't const since they may modify the recursion protection sets).
std::vector<const NamedDecl *>
resolveMemberExpr(const CXXDependentScopeMemberExpr *ME);
std::vector<const NamedDecl *>
resolveDeclRefExpr(const DependentScopeDeclRefExpr *RE);
std::vector<const NamedDecl *> resolveTypeOfCallExpr(const CallExpr *CE);
std::vector<const NamedDecl *> resolveCalleeOfCallExpr(const CallExpr *CE);
std::vector<const NamedDecl *>
resolveUsingValueDecl(const UnresolvedUsingValueDecl *UUVD);
std::vector<const NamedDecl *>
resolveDependentNameType(const DependentNameType *DNT);
std::vector<const NamedDecl *> resolveTemplateSpecializationType(
const DependentTemplateSpecializationType *DTST);
const Type *resolveNestedNameSpecifierToType(const NestedNameSpecifier *NNS);
const Type *getPointeeType(const Type *T);

private:
ASTContext &Ctx;

// Recursion protection sets
llvm::SmallSet<const DependentNameType *, 4> SeenDependentNameTypes;

// Given a tag-decl type and a member name, heuristically resolve the
// name to one or more declarations.
// The current heuristic is simply to look up the name in the primary
// template. This is a heuristic because the template could potentially
// have specializations that declare different members.
// Multiple declarations could be returned if the name is overloaded
// (e.g. an overloaded method in the primary template).
// This heuristic will give the desired answer in many cases, e.g.
// for a call to vector<T>::size().
std::vector<const NamedDecl *>
resolveDependentMember(const Type *T, DeclarationName Name,
llvm::function_ref<bool(const NamedDecl *ND)> Filter);

// Try to heuristically resolve the type of a possibly-dependent expression
// `E`.
const Type *resolveExprToType(const Expr *E);
std::vector<const NamedDecl *> resolveExprToDecls(const Expr *E);

// Helper function for HeuristicResolver::resolveDependentMember()
// which takes a possibly-dependent type `T` and heuristically
// resolves it to a CXXRecordDecl in which we can try name lookup.
CXXRecordDecl *resolveTypeToRecordDecl(const Type *T);

// This is a reimplementation of CXXRecordDecl::lookupDependentName()
// so that the implementation can call into other HeuristicResolver helpers.
// FIXME: Once HeuristicResolver is upstreamed to the clang libraries
// (https://github.com/clangd/clangd/discussions/1662),
// CXXRecordDecl::lookupDepenedentName() can be removed, and its call sites
// can be modified to benefit from the more comprehensive heuristics offered
// by HeuristicResolver instead.
std::vector<const NamedDecl *>
lookupDependentName(CXXRecordDecl *RD, DeclarationName Name,
llvm::function_ref<bool(const NamedDecl *ND)> Filter);
bool findOrdinaryMemberInDependentClasses(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
DeclarationName Name);
};

// Convenience lambdas for use as the 'Filter' parameter of
// HeuristicResolver::resolveDependentMember().
const auto NoFilter = [](const NamedDecl *D) { return true; };
Expand All @@ -31,8 +105,6 @@ const auto TemplateFilter = [](const NamedDecl *D) {
return isa<TemplateDecl>(D);
};

namespace {

const Type *resolveDeclsToType(const std::vector<const NamedDecl *> &Decls,
ASTContext &Ctx) {
if (Decls.size() != 1) // Names an overload set -- just bail.
Expand All @@ -46,12 +118,10 @@ const Type *resolveDeclsToType(const std::vector<const NamedDecl *> &Decls,
return nullptr;
}

} // namespace

// Helper function for HeuristicResolver::resolveDependentMember()
// which takes a possibly-dependent type `T` and heuristically
// resolves it to a CXXRecordDecl in which we can try name lookup.
CXXRecordDecl *HeuristicResolver::resolveTypeToRecordDecl(const Type *T) const {
CXXRecordDecl *HeuristicResolverImpl::resolveTypeToRecordDecl(const Type *T) {
assert(T);

// Unwrap type sugar such as type aliases.
Expand Down Expand Up @@ -84,7 +154,7 @@ CXXRecordDecl *HeuristicResolver::resolveTypeToRecordDecl(const Type *T) const {
return TD->getTemplatedDecl();
}

const Type *HeuristicResolver::getPointeeType(const Type *T) const {
const Type *HeuristicResolverImpl::getPointeeType(const Type *T) {
if (!T)
return nullptr;

Expand Down Expand Up @@ -117,8 +187,8 @@ const Type *HeuristicResolver::getPointeeType(const Type *T) const {
return FirstArg.getAsType().getTypePtrOrNull();
}

std::vector<const NamedDecl *> HeuristicResolver::resolveMemberExpr(
const CXXDependentScopeMemberExpr *ME) const {
std::vector<const NamedDecl *> HeuristicResolverImpl::resolveMemberExpr(
const CXXDependentScopeMemberExpr *ME) {
// If the expression has a qualifier, try resolving the member inside the
// qualifier's type.
// Note that we cannot use a NonStaticFilter in either case, for a couple
Expand Down Expand Up @@ -164,14 +234,14 @@ std::vector<const NamedDecl *> HeuristicResolver::resolveMemberExpr(
return resolveDependentMember(BaseType, ME->getMember(), NoFilter);
}

std::vector<const NamedDecl *> HeuristicResolver::resolveDeclRefExpr(
const DependentScopeDeclRefExpr *RE) const {
std::vector<const NamedDecl *>
HeuristicResolverImpl::resolveDeclRefExpr(const DependentScopeDeclRefExpr *RE) {
return resolveDependentMember(RE->getQualifier()->getAsType(),
RE->getDeclName(), StaticFilter);
}

std::vector<const NamedDecl *>
HeuristicResolver::resolveTypeOfCallExpr(const CallExpr *CE) const {
HeuristicResolverImpl::resolveTypeOfCallExpr(const CallExpr *CE) {
const auto *CalleeType = resolveExprToType(CE->getCallee());
if (!CalleeType)
return {};
Expand All @@ -187,37 +257,39 @@ HeuristicResolver::resolveTypeOfCallExpr(const CallExpr *CE) const {
}

std::vector<const NamedDecl *>
HeuristicResolver::resolveCalleeOfCallExpr(const CallExpr *CE) const {
HeuristicResolverImpl::resolveCalleeOfCallExpr(const CallExpr *CE) {
if (const auto *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) {
return {ND};
}

return resolveExprToDecls(CE->getCallee());
}

std::vector<const NamedDecl *> HeuristicResolver::resolveUsingValueDecl(
const UnresolvedUsingValueDecl *UUVD) const {
std::vector<const NamedDecl *> HeuristicResolverImpl::resolveUsingValueDecl(
const UnresolvedUsingValueDecl *UUVD) {
return resolveDependentMember(UUVD->getQualifier()->getAsType(),
UUVD->getNameInfo().getName(), ValueFilter);
}

std::vector<const NamedDecl *> HeuristicResolver::resolveDependentNameType(
const DependentNameType *DNT) const {
std::vector<const NamedDecl *>
HeuristicResolverImpl::resolveDependentNameType(const DependentNameType *DNT) {
if (auto [_, inserted] = SeenDependentNameTypes.insert(DNT); !inserted)
return {};
return resolveDependentMember(
resolveNestedNameSpecifierToType(DNT->getQualifier()),
DNT->getIdentifier(), TypeFilter);
}

std::vector<const NamedDecl *>
HeuristicResolver::resolveTemplateSpecializationType(
const DependentTemplateSpecializationType *DTST) const {
HeuristicResolverImpl::resolveTemplateSpecializationType(
const DependentTemplateSpecializationType *DTST) {
return resolveDependentMember(
resolveNestedNameSpecifierToType(DTST->getQualifier()),
DTST->getIdentifier(), TemplateFilter);
}

std::vector<const NamedDecl *>
HeuristicResolver::resolveExprToDecls(const Expr *E) const {
HeuristicResolverImpl::resolveExprToDecls(const Expr *E) {
if (const auto *ME = dyn_cast<CXXDependentScopeMemberExpr>(E)) {
return resolveMemberExpr(ME);
}
Expand All @@ -236,16 +308,16 @@ HeuristicResolver::resolveExprToDecls(const Expr *E) const {
return {};
}

const Type *HeuristicResolver::resolveExprToType(const Expr *E) const {
const Type *HeuristicResolverImpl::resolveExprToType(const Expr *E) {
std::vector<const NamedDecl *> Decls = resolveExprToDecls(E);
if (!Decls.empty())
return resolveDeclsToType(Decls, Ctx);

return E->getType().getTypePtr();
}

const Type *HeuristicResolver::resolveNestedNameSpecifierToType(
const NestedNameSpecifier *NNS) const {
const Type *HeuristicResolverImpl::resolveNestedNameSpecifierToType(
const NestedNameSpecifier *NNS) {
if (!NNS)
return nullptr;

Expand All @@ -270,8 +342,6 @@ const Type *HeuristicResolver::resolveNestedNameSpecifierToType(
return nullptr;
}

namespace {

bool isOrdinaryMember(const NamedDecl *ND) {
return ND->isInIdentifierNamespace(Decl::IDNS_Ordinary | Decl::IDNS_Tag |
Decl::IDNS_Member);
Expand All @@ -287,21 +357,19 @@ bool findOrdinaryMember(const CXXRecordDecl *RD, CXXBasePath &Path,
return false;
}

} // namespace

bool HeuristicResolver::findOrdinaryMemberInDependentClasses(
bool HeuristicResolverImpl::findOrdinaryMemberInDependentClasses(
const CXXBaseSpecifier *Specifier, CXXBasePath &Path,
DeclarationName Name) const {
DeclarationName Name) {
CXXRecordDecl *RD =
resolveTypeToRecordDecl(Specifier->getType().getTypePtr());
if (!RD)
return false;
return findOrdinaryMember(RD, Path, Name);
}

std::vector<const NamedDecl *> HeuristicResolver::lookupDependentName(
std::vector<const NamedDecl *> HeuristicResolverImpl::lookupDependentName(
CXXRecordDecl *RD, DeclarationName Name,
llvm::function_ref<bool(const NamedDecl *ND)> Filter) const {
llvm::function_ref<bool(const NamedDecl *ND)> Filter) {
std::vector<const NamedDecl *> Results;

// Lookup in the class.
Expand Down Expand Up @@ -332,9 +400,9 @@ std::vector<const NamedDecl *> HeuristicResolver::lookupDependentName(
return Results;
}

std::vector<const NamedDecl *> HeuristicResolver::resolveDependentMember(
std::vector<const NamedDecl *> HeuristicResolverImpl::resolveDependentMember(
const Type *T, DeclarationName Name,
llvm::function_ref<bool(const NamedDecl *ND)> Filter) const {
llvm::function_ref<bool(const NamedDecl *ND)> Filter) {
if (!T)
return {};
if (auto *ET = T->getAs<EnumType>()) {
Expand All @@ -349,6 +417,44 @@ std::vector<const NamedDecl *> HeuristicResolver::resolveDependentMember(
}
return {};
}
} // namespace

std::vector<const NamedDecl *> HeuristicResolver::resolveMemberExpr(
const CXXDependentScopeMemberExpr *ME) const {
return HeuristicResolverImpl(Ctx).resolveMemberExpr(ME);
}
std::vector<const NamedDecl *> HeuristicResolver::resolveDeclRefExpr(
const DependentScopeDeclRefExpr *RE) const {
return HeuristicResolverImpl(Ctx).resolveDeclRefExpr(RE);
}
std::vector<const NamedDecl *>
HeuristicResolver::resolveTypeOfCallExpr(const CallExpr *CE) const {
return HeuristicResolverImpl(Ctx).resolveTypeOfCallExpr(CE);
}
std::vector<const NamedDecl *>
HeuristicResolver::resolveCalleeOfCallExpr(const CallExpr *CE) const {
return HeuristicResolverImpl(Ctx).resolveCalleeOfCallExpr(CE);
}
std::vector<const NamedDecl *> HeuristicResolver::resolveUsingValueDecl(
const UnresolvedUsingValueDecl *UUVD) const {
return HeuristicResolverImpl(Ctx).resolveUsingValueDecl(UUVD);
}
std::vector<const NamedDecl *> HeuristicResolver::resolveDependentNameType(
const DependentNameType *DNT) const {
return HeuristicResolverImpl(Ctx).resolveDependentNameType(DNT);
}
std::vector<const NamedDecl *>
HeuristicResolver::resolveTemplateSpecializationType(
const DependentTemplateSpecializationType *DTST) const {
return HeuristicResolverImpl(Ctx).resolveTemplateSpecializationType(DTST);
}
const Type *HeuristicResolver::resolveNestedNameSpecifierToType(
const NestedNameSpecifier *NNS) const {
return HeuristicResolverImpl(Ctx).resolveNestedNameSpecifierToType(NNS);
}
const Type *HeuristicResolver::getPointeeType(const Type *T) const {
return HeuristicResolverImpl(Ctx).getPointeeType(T);
}

} // namespace clangd
} // namespace clang
37 changes: 0 additions & 37 deletions clang-tools-extra/clangd/HeuristicResolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,43 +77,6 @@ class HeuristicResolver {

private:
ASTContext &Ctx;

// Given a tag-decl type and a member name, heuristically resolve the
// name to one or more declarations.
// The current heuristic is simply to look up the name in the primary
// template. This is a heuristic because the template could potentially
// have specializations that declare different members.
// Multiple declarations could be returned if the name is overloaded
// (e.g. an overloaded method in the primary template).
// This heuristic will give the desired answer in many cases, e.g.
// for a call to vector<T>::size().
std::vector<const NamedDecl *> resolveDependentMember(
const Type *T, DeclarationName Name,
llvm::function_ref<bool(const NamedDecl *ND)> Filter) const;

// Try to heuristically resolve the type of a possibly-dependent expression
// `E`.
const Type *resolveExprToType(const Expr *E) const;
std::vector<const NamedDecl *> resolveExprToDecls(const Expr *E) const;

// Helper function for HeuristicResolver::resolveDependentMember()
// which takes a possibly-dependent type `T` and heuristically
// resolves it to a CXXRecordDecl in which we can try name lookup.
CXXRecordDecl *resolveTypeToRecordDecl(const Type *T) const;

// This is a reimplementation of CXXRecordDecl::lookupDependentName()
// so that the implementation can call into other HeuristicResolver helpers.
// FIXME: Once HeuristicResolver is upstreamed to the clang libraries
// (https://github.com/clangd/clangd/discussions/1662),
// CXXRecordDecl::lookupDepenedentName() can be removed, and its call sites
// can be modified to benefit from the more comprehensive heuristics offered
// by HeuristicResolver instead.
std::vector<const NamedDecl *> lookupDependentName(
CXXRecordDecl *RD, DeclarationName Name,
llvm::function_ref<bool(const NamedDecl *ND)> Filter) const;
bool findOrdinaryMemberInDependentClasses(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
DeclarationName Name) const;
};

} // namespace clangd
Expand Down
27 changes: 27 additions & 0 deletions clang-tools-extra/clangd/unittests/FindTargetTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1009,6 +1009,33 @@ TEST_F(TargetDeclTest, DependentTypes) {
)cpp";
EXPECT_DECLS("DependentTemplateSpecializationTypeLoc",
"template <typename> struct B");

// Dependent name with recursive definition. We don't expect a
// result, but we shouldn't get into a stack overflow either.
Code = R"cpp(
template <int N>
struct waldo {
typedef typename waldo<N - 1>::type::[[next]] type;
};
)cpp";
EXPECT_DECLS("DependentNameTypeLoc");

// Similar to above but using mutually recursive templates.
Code = R"cpp(
template <int N>
struct odd;
template <int N>
struct even {
using type = typename odd<N - 1>::type::next;
};
template <int N>
struct odd {
using type = typename even<N - 1>::type::[[next]];
};
)cpp";
EXPECT_DECLS("DependentNameTypeLoc");
}

TEST_F(TargetDeclTest, TypedefCascade) {
Expand Down
8 changes: 8 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ Changes in existing checks
<clang-tidy/checks/bugprone/unused-local-non-trivial-variable>` check by
ignoring local variable with ``[maybe_unused]`` attribute.

- Improved :doc:`bugprone-unused-return-value
<clang-tidy/checks/bugprone/unused-return-value>` check by updating the
parameter `CheckedFunctions` to support regexp.

- Improved :doc:`cppcoreguidelines-missing-std-forward
<clang-tidy/checks/cppcoreguidelines/missing-std-forward>` check by no longer
giving false positives for deleted functions.
Expand All @@ -157,6 +161,10 @@ Changes in existing checks
<clang-tidy/checks/google/build-namespaces>` check by replacing the local
option `HeaderFileExtensions` by the global option of the same name.

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

- Improved :doc:`google-global-names-in-headers
<clang-tidy/checks/google/global-names-in-headers>` check by replacing the local
option `HeaderFileExtensions` by the global option of the same name.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ Options

.. option:: CheckedFunctions

Semicolon-separated list of functions to check. The function is checked if
the name and scope matches, with any arguments.
Semicolon-separated list of functions to check.
This parameter supports regexp. The function is checked if the name
and scope matches, with any arguments.
By default the following functions are checked:
``std::async, std::launder, std::remove, std::remove_if, std::unique,
std::unique_ptr::release, std::basic_string::empty, std::vector::empty,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// RUN: %check_clang_tidy %s bugprone-unused-return-value %t \
// RUN: -config='{CheckOptions: \
// RUN: {bugprone-unused-return-value.CheckedFunctions: \
// RUN: "::fun;::ns::Outer::Inner::memFun;::ns::Type::staticFun;::ns::ClassTemplate::memFun;::ns::ClassTemplate::staticFun"}}' \
// RUN: "::fun;::ns::Outer::Inner::memFun;::ns::Type::staticFun;::ns::ClassTemplate::(mem|static)Fun"}}' \
// RUN: --

namespace std {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// RUN: %check_clang_tidy %s google-explicit-constructor %t -std=c++20-or-later

namespace issue_81121
{

static constexpr bool ConstFalse = false;
static constexpr bool ConstTrue = true;

struct A {
explicit(true) A(int);
};

struct B {
explicit(false) B(int);
};

struct C {
explicit(ConstTrue) C(int);
};

struct D {
explicit(ConstFalse) D(int);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: single-argument constructors explicit expression evaluates to 'false' [google-explicit-constructor]
};

template <typename>
struct E {
explicit(true) E(int);
};

template <typename>
struct F {
explicit(false) F(int);
};

template <typename>
struct G {
explicit(ConstTrue) G(int);
};

template <typename>
struct H {
explicit(ConstFalse) H(int);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: single-argument constructors explicit expression evaluates to 'false' [google-explicit-constructor]
};

template <int Val>
struct I {
explicit(Val > 0) I(int);
};

template <int Val>
struct J {
explicit(Val > 0) J(int);
};

void useJ(J<0>, J<100>);

} // namespace issue_81121
101 changes: 46 additions & 55 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ C/C++ Language Potentially Breaking Changes

C++ Specific Potentially Breaking Changes
-----------------------------------------
- Clang now diagnoses function/variable templates that shadow their own template parameters, e.g. ``template<class T> void T();``.
This error can be disabled via `-Wno-strict-primary-template-shadow` for compatibility with previous versions of clang.

ABI Changes in This Version
---------------------------
Expand Down Expand Up @@ -79,7 +81,7 @@ C++20 Feature Support
more to ease the implementation and improve the user's using experience.
This follows the MSVC's behavior. Users interested in testing the more strict
behavior can use the flag '-Xclang -fno-skip-odr-check-in-gmf'.
(`#79240 <https://github.com/llvm/llvm-project/issues/79240>`_).
(#GH79240).

- Implemented the `__is_layout_compatible` intrinsic to support
`P0466R5: Layout-compatibility and Pointer-interconvertibility Traits <https://wg21.link/P0466R5>`_.
Expand Down Expand Up @@ -116,7 +118,7 @@ C Language Changes
C23 Feature Support
^^^^^^^^^^^^^^^^^^^
- No longer diagnose use of binary literals as an extension in C23 mode. Fixes
`#72017 <https://github.com/llvm/llvm-project/issues/72017>`_.
#GH72017.

- Corrected parsing behavior for the ``alignas`` specifier/qualifier in C23. We
previously handled it as an attribute as in C++, but there are parsing
Expand All @@ -129,7 +131,7 @@ C23 Feature Support
};
int i alignas(8) /* was accepted, now rejected */ ;
Fixes (`#81472 <https://github.com/llvm/llvm-project/issues/81472>`_).
Fixes (#GH81472).

- Clang now generates predefined macros of the form ``__TYPE_FMTB__`` and
``__TYPE_FMTb__`` (e.g., ``__UINT_FAST64_FMTB__``) in C23 mode for use with
Expand Down Expand Up @@ -173,7 +175,7 @@ Improvements to Clang's diagnostics
name specifiers.

- The ``-Wshorten-64-to-32`` diagnostic is now grouped under ``-Wimplicit-int-conversion`` instead
of ``-Wconversion``. Fixes `#69444 <https://github.com/llvm/llvm-project/issues/69444>`_.
of ``-Wconversion``. Fixes #GH69444.

- Clang now diagnoses friend declarations with an ``enum`` elaborated-type-specifier in language modes after C++98.

Expand All @@ -186,14 +188,14 @@ Improvements to Clang's diagnostics
``unsigned long long``, but this behavior may change in the future when Clang
implements
`WG14 N3029 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3029.htm>`_.
Fixes `#69352 <https://github.com/llvm/llvm-project/issues/69352>`_.
(#GH69352).

- Clang now diagnoses extraneous template parameter lists as a language extension.

- Clang now diagnoses declarative nested name specifiers that name alias templates.

- Clang now diagnoses lambda function expressions being implicitly cast to boolean values, under ``-Wpointer-bool-conversion``.
Fixes `#82512 <https://github.com/llvm/llvm-project/issues/82512>`_.
Fixes #GH82512.

Improvements to Clang's time-trace
----------------------------------
Expand All @@ -206,21 +208,21 @@ Bug Fixes in This Version
- Clang now accepts elaborated-type-specifiers that explicitly specialize
a member class template for an implicit instantiation of a class template.

- Fixed missing warnings when doing bool-like conversions in C23 (`#79435 <https://github.com/llvm/llvm-project/issues/79435>`_).
- Fixed missing warnings when doing bool-like conversions in C23 (#GH79435).
- Clang's ``-Wshadow`` no longer warns when an init-capture is named the same as
a class field unless the lambda can capture this.
Fixes (`#71976 <https://github.com/llvm/llvm-project/issues/71976>`_)
Fixes (#GH71976)

- Clang now accepts qualified partial/explicit specializations of variable templates that
are not nominable in the lookup context of the specialization.

- Clang now doesn't produce false-positive warning `-Wconstant-logical-operand`
for logical operators in C23.
Fixes (`#64356 <https://github.com/llvm/llvm-project/issues/64356>`_).
Fixes (#GH64356).

- Clang no longer produces a false-positive `-Wunused-variable` warning
for variables created through copy initialization having side-effects in C++17 and later.
Fixes (`#79518 <https://github.com/llvm/llvm-project/issues/79518>`_).
Fixes (#GH64356) (#GH79518).

Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -232,85 +234,70 @@ Bug Fixes to C++ Support
^^^^^^^^^^^^^^^^^^^^^^^^

- Fix crash when calling the constructor of an invalid class.
Fixes (`#10518 <https://github.com/llvm/llvm-project/issues/10518>`_),
(`#67914 <https://github.com/llvm/llvm-project/issues/10518>`_),
and (`#78388 <https://github.com/llvm/llvm-project/issues/78388>`_)
(#GH10518) (#GH67914) (#GH78388)
- Fix crash when using lifetimebound attribute in function with trailing return.
Fixes (`#73619 <https://github.com/llvm/llvm-project/issues/73619>`_)
(#GH73619)
- Addressed an issue where constraints involving injected class types are perceived
distinct from its specialization types.
(`#56482 <https://github.com/llvm/llvm-project/issues/56482>`_)
distinct from its specialization types. (#GH56482)
- Fixed a bug where variables referenced by requires-clauses inside
nested generic lambdas were not properly injected into the constraint scope.
(`#73418 <https://github.com/llvm/llvm-project/issues/73418>`_)
nested generic lambdas were not properly injected into the constraint scope. (#GH73418)
- Fixed a crash where substituting into a requires-expression that refers to function
parameters during the equivalence determination of two constraint expressions.
(`#74447 <https://github.com/llvm/llvm-project/issues/74447>`_)
(#GH74447)
- Fixed deducing auto& from const int in template parameters of partial
specializations.
(`#77189 <https://github.com/llvm/llvm-project/issues/77189>`_)
specializations. (#GH77189)
- Fix for crash when using a erroneous type in a return statement.
Fixes (`#63244 <https://github.com/llvm/llvm-project/issues/63244>`_)
and (`#79745 <https://github.com/llvm/llvm-project/issues/79745>`_)
(#GH63244) (#GH79745)
- Fixed an out-of-bounds error caused by building a recovery expression for ill-formed
function calls while substituting into constraints.
(`#58548 <https://github.com/llvm/llvm-project/issues/58548>`_)
- Fix incorrect code generation caused by the object argument of ``static operator()`` and ``static operator[]`` calls not being evaluated.
Fixes (`#67976 <https://github.com/llvm/llvm-project/issues/67976>`_)
function calls while substituting into constraints. (#GH58548)
- Fix incorrect code generation caused by the object argument
of ``static operator()`` and ``static operator[]`` calls not being evaluated. (#GH67976)
- Fix crash and diagnostic with const qualified member operator new.
Fixes (`#79748 <https://github.com/llvm/llvm-project/issues/79748>`_)
Fixes (#GH79748)
- Fixed a crash where substituting into a requires-expression that involves parameter packs
during the equivalence determination of two constraint expressions.
(`#72557 <https://github.com/llvm/llvm-project/issues/72557>`_)
during the equivalence determination of two constraint expressions. (#GH72557)
- Fix a crash when specializing an out-of-line member function with a default
parameter where we did an incorrect specialization of the initialization of
the default parameter.
Fixes (`#68490 <https://github.com/llvm/llvm-project/issues/68490>`_)
the default parameter. (#GH68490)
- Fix a crash when trying to call a varargs function that also has an explicit object parameter.
Fixes (`#80971 ICE when explicit object parameter be a function parameter pack`)
- Reject explicit object parameters on `new` and `delete` operators.
Fixes (`#82249 <https://github.com/llvm/llvm-project/issues/82249>` _)
Fixes (#GH80971)
- Reject explicit object parameters on `new` and `delete` operators. (#GH82249)
- Fix a crash when trying to call a varargs function that also has an explicit object parameter. (#GH80971)
- Fixed a bug where abbreviated function templates would append their invented template parameters to
an empty template parameter lists.
- Clang now classifies aggregate initialization in C++17 and newer as constant
or non-constant more accurately. Previously, only a subset of the initializer
elements were considered, misclassifying some initializers as constant. Fixes
some of (`#80510 <https://github.com/llvm/llvm-project/issues/80510>`).
- Clang now ignores top-level cv-qualifiers on function parameters in template partial orderings.
(`#75404 <https://github.com/llvm/llvm-project/issues/75404>`_)
elements were considered, misclassifying some initializers as constant. Partially fixes
#GH80510.
- Clang now ignores top-level cv-qualifiers on function parameters in template partial orderings. (#GH75404)
- No longer reject valid use of the ``_Alignas`` specifier when declaring a
local variable, which is supported as a C11 extension in C++. Previously, it
was only accepted at namespace scope but not at local function scope.
- Clang no longer tries to call consteval constructors at runtime when they appear in a member initializer.
(`#82154 <https://github.com/llvm/llvm-project/issues/82154>`_`)
- Fix crash when using an immediate-escalated function at global scope.
(`#82258 <https://github.com/llvm/llvm-project/issues/82258>`_)
- Correctly immediate-escalate lambda conversion functions.
(`#82258 <https://github.com/llvm/llvm-project/issues/82258>`_)
- Clang no longer tries to call consteval constructors at runtime when they appear in a member initializer. (#GH82154)
- Fix crash when using an immediate-escalated function at global scope. (#GH82258)
- Correctly immediate-escalate lambda conversion functions. (#GH82258)
- Fixed an issue where template parameters of a nested abbreviated generic lambda within
a requires-clause lie at the same depth as those of the surrounding lambda. This,
in turn, results in the wrong template argument substitution during constraint checking.
(`#78524 <https://github.com/llvm/llvm-project/issues/78524>`_)
(#GH78524)
- Clang no longer instantiates the exception specification of discarded candidate function
templates when determining the primary template of an explicit specialization.
- Fixed a crash in Microsoft compatibility mode where unqualified dependent base class
lookup searches the bases of an incomplete class.
- Fix a crash when an unresolved overload set is encountered on the RHS of a ``.*`` operator.
(`#53815 <https://github.com/llvm/llvm-project/issues/53815>`_)
(#GH53815)
- In ``__restrict``-qualified member functions, attach ``__restrict`` to the pointer type of
``this`` rather than the pointee type.
Fixes (`#82941 <https://github.com/llvm/llvm-project/issues/82941>`_),
(`#42411 <https://github.com/llvm/llvm-project/issues/42411>`_), and
(`#18121 <https://github.com/llvm/llvm-project/issues/18121>`_).
Fixes (#GH82941), (#GH42411) and (#GH18121).
- Clang now properly reports supported C++11 attributes when using
``__has_cpp_attribute`` and parses attributes with arguments in C++03
(`#82995 <https://github.com/llvm/llvm-project/issues/82995>`_)
``__has_cpp_attribute`` and parses attributes with arguments in C++03 (#GH82995)
- Clang now properly diagnoses missing 'default' template arguments on a variety
of templates. Previously we were diagnosing on any non-function template
instead of only on class, alias, and variable templates, as last updated by
CWG2032.
Fixes (`#83461 <https://github.com/llvm/llvm-project/issues/83461>`_)

CWG2032. Fixes (#GH83461)
- Fixed an issue where an attribute on a declarator would cause the attribute to
be destructed prematurely. This fixes a pair of Chromium that were brought to
our attention by an attempt to fix in (#GH77703). Fixes (#GH83385).

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -321,6 +308,10 @@ Miscellaneous Bug Fixes
Miscellaneous Clang Crashes Fixed
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

- Do not attempt to dump the layout of dependent types or invalid declarations
when ``-fdump-record-layouts-complete`` is passed.
Fixes (`#83684 <https://github.com/llvm/llvm-project/issues/83684>`_).

OpenACC Specific Changes
------------------------

Expand Down
21 changes: 17 additions & 4 deletions clang/docs/analyzer/checkers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1320,10 +1320,23 @@ range of the argument.
**Parameters**
The checker models functions (and emits diagnostics) from the C standard by
default. The ``ModelPOSIX`` option enables modeling (and emit diagnostics) of
additional functions that are defined in the POSIX standard. This option is
disabled by default.
The ``ModelPOSIX`` option controls if functions from the POSIX standard are
recognized by the checker.
With ``ModelPOSIX=true``, many POSIX functions are modeled according to the
`POSIX standard`_. This includes ranges of parameters and possible return
values. Furthermore the behavior related to ``errno`` in the POSIX case is
often that ``errno`` is set only if a function call fails, and it becomes
undefined after a successful function call.
With ``ModelPOSIX=false``, this checker follows the C99 language standard and
only models the functions that are described there. It is possible that the
same functions are modeled differently in the two cases because differences in
the standards. The C standard specifies less aspects of the functions, for
example exact ``errno`` behavior is often unspecified (and not modeled by the
checker).
Default value of the option is ``true``.
.. _osx-checkers:
Expand Down
15 changes: 12 additions & 3 deletions clang/docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
# sys.path.insert(0, os.path.abspath('.'))
sys.path.insert(0, os.path.abspath("."))

# -- General configuration -----------------------------------------------------

Expand All @@ -27,16 +27,25 @@

# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ["sphinx.ext.todo", "sphinx.ext.mathjax", "sphinx.ext.graphviz"]
extensions = ["sphinx.ext.todo", "sphinx.ext.mathjax", "sphinx.ext.graphviz", "ghlinks"]

# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]


import sphinx

if sphinx.version_info >= (3, 0):
# When building man pages, we do not use the markdown pages,
# So, we can continue without the myst_parser dependencies.
# Doing so reduces dependencies of some packaged llvm distributions.
try:
import myst_parser

extensions.append("myst_parser")
except ImportError:
if not tags.has("builder-man"):
raise


# The encoding of source files.
# source_encoding = 'utf-8-sig'
Expand Down
19 changes: 19 additions & 0 deletions clang/docs/ghlinks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/env python3

from sphinx.application import Sphinx
import re

__version__ = "1.0"


def subst_gh_links(app: Sphinx, docname, source):
regex = re.compile("#GH([0-9]+)")
out_pattern = r"`#\1 <https://github.com/llvm/llvm-project/issues/\1>`_"
result = source[0]
result = regex.sub(out_pattern, result)
source[0] = result


def setup(app: Sphinx):
app.connect("source-read", subst_gh_links)
return dict(version=__version__, parallel_read_safe=True, parallel_write_safe=True)
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -4977,6 +4977,9 @@ def err_template_param_shadow : Error<
"declaration of %0 shadows template parameter">;
def ext_template_param_shadow : ExtWarn<
err_template_param_shadow.Summary>, InGroup<MicrosoftTemplateShadow>;
def ext_compat_template_param_shadow : ExtWarn<
err_template_param_shadow.Summary>, InGroup<
DiagGroup<"strict-primary-template-shadow">>, DefaultError;
def note_template_param_here : Note<"template parameter is declared here">;
def note_template_param_external : Note<
"template parameter from hidden source: %0">;
Expand Down
5 changes: 0 additions & 5 deletions clang/include/clang/Driver/Driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,9 +160,6 @@ class Driver {
/// Target and driver mode components extracted from clang executable name.
ParsedClangName ClangNameParts;

/// TODO: Remove this in favor of Dir.
std::string InstalledDir;

/// The path to the compiler resource directory.
std::string ResourceDir;

Expand Down Expand Up @@ -429,8 +426,6 @@ class Driver {

/// Get the path to where the clang executable was installed.
const char *getInstalledDir() const {
if (!InstalledDir.empty())
return InstalledDir.c_str();
return Dir.c_str();
}

Expand Down
16 changes: 16 additions & 0 deletions clang/include/clang/Sema/DeclSpec.h
Original file line number Diff line number Diff line change
Expand Up @@ -2359,11 +2359,27 @@ class Declarator {
SetRangeEnd(EndLoc);
}

/// AddTypeInfo - Add a chunk to this declarator. Also extend the range to
/// EndLoc, which should be the last token of the chunk. This overload is for
/// copying a 'chunk' from another declarator, so it takes the pool that the
/// other Declarator owns so that it can 'take' the attributes from it.
void AddTypeInfo(const DeclaratorChunk &TI, AttributePool &OtherPool,
SourceLocation EndLoc) {
DeclTypeInfo.push_back(TI);
getAttributePool().takeFrom(DeclTypeInfo.back().getAttrs(), OtherPool);

if (!EndLoc.isInvalid())
SetRangeEnd(EndLoc);
}

/// AddTypeInfo - Add a chunk to this declarator. Also extend the range to
/// EndLoc, which should be the last token of the chunk.
void AddTypeInfo(const DeclaratorChunk &TI, SourceLocation EndLoc) {
DeclTypeInfo.push_back(TI);

assert(TI.AttrList.empty() &&
"Cannot add a declarator chunk with attributes with this overload");

if (!EndLoc.isInvalid())
SetRangeEnd(EndLoc);
}
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Sema/ParsedAttr.h
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,7 @@ class AttributeFactory {
~AttributeFactory();
};

class ParsedAttributesView;
class AttributePool {
friend class AttributeFactory;
friend class ParsedAttributes;
Expand Down Expand Up @@ -734,6 +735,10 @@ class AttributePool {
pool.Attrs.clear();
}

/// Removes the attributes from \c List, which are owned by \c Pool, and adds
/// them at the end of this \c AttributePool.
void takeFrom(ParsedAttributesView &List, AttributePool &Pool);

ParsedAttr *create(IdentifierInfo *attrName, SourceRange attrRange,
IdentifierInfo *scopeName, SourceLocation scopeLoc,
ArgsUnion *args, unsigned numArgs, ParsedAttr::Form form,
Expand Down Expand Up @@ -816,6 +821,7 @@ class AttributePool {
};

class ParsedAttributesView {
friend class AttributePool;
using VecTy = llvm::SmallVector<ParsedAttr *>;
using SizeType = decltype(std::declval<VecTy>().size());

Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/Sema/Scope.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,10 @@ class Scope {
/// other template parameter scopes as parents.
Scope *TemplateParamParent;

/// DeclScopeParent - This is a direct link to the immediately containing
/// DeclScope, i.e. scope which can contain declarations.
Scope *DeclParent;

/// DeclsInScope - This keeps track of all declarations in this scope. When
/// the declaration is added to the scope, it is set as the current
/// declaration for the identifier in the IdentifierTable. When the scope is
Expand Down Expand Up @@ -305,6 +309,9 @@ class Scope {
Scope *getTemplateParamParent() { return TemplateParamParent; }
const Scope *getTemplateParamParent() const { return TemplateParamParent; }

Scope *getDeclParent() { return DeclParent; }
const Scope *getDeclParent() const { return DeclParent; }

/// Returns the depth of this scope. The translation-unit has scope depth 0.
unsigned getDepth() const { return Depth; }

Expand Down
16 changes: 15 additions & 1 deletion clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -8386,7 +8386,21 @@ class Sema final {
TemplateSpecializationKind TSK,
bool Complain = true);

void DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl);
/// DiagnoseTemplateParameterShadow - Produce a diagnostic complaining
/// that the template parameter 'PrevDecl' is being shadowed by a new
/// declaration at location Loc. Returns true to indicate that this is
/// an error, and false otherwise.
///
/// \param Loc The location of the declaration that shadows a template
/// parameter.
///
/// \param PrevDecl The template parameter that the declaration shadows.
///
/// \param SupportedForCompatibility Whether to issue the diagnostic as
/// a warning for compatibility with older versions of clang.
/// Ignored when MSVC compatibility is enabled.
void DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl,
bool SupportedForCompatibility = false);
TemplateDecl *AdjustDeclIfTemplate(Decl *&Decl);

NamedDecl *ActOnTypeParameter(Scope *S, bool Typename,
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,7 @@ def StdCLibraryFunctionsChecker : Checker<"StdCLibraryFunctions">,
"ModelPOSIX",
"If set to true, the checker models additional functions "
"from the POSIX standard.",
"false",
"true",
InAlpha>
]>,
WeakDependencies<[CallAndMessageChecker, NonNullParamChecker]>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,48 @@ class IdentifierInfo;

namespace clang {
namespace ento {

enum CallDescriptionFlags : unsigned {
CDF_None = 0,

/// Describes a C standard function that is sometimes implemented as a macro
/// that expands to a compiler builtin with some __builtin prefix.
/// The builtin may as well have a few extra arguments on top of the requested
/// number of arguments.
CDF_MaybeBuiltin = 1 << 0,
};

/// This class represents a description of a function call using the number of
/// arguments and the name of the function.
/// A `CallDescription` is a pattern that can be used to _match_ calls
/// based on the qualified name and the argument/parameter counts.
class CallDescription {
public:
enum class Mode {
/// Match calls to functions from the C standard library. On some platforms
/// some functions may be implemented as macros that expand to calls to
/// built-in variants of the given functions, so in this mode we use some
/// heuristics to recognize these implementation-defined variants:
/// - We also accept calls where the name is derived from the specified
/// name by adding "__builtin" or similar prefixes/suffixes.
/// - We also accept calls where the number of arguments or parameters is
/// greater than the specified value.
/// For the exact heuristics, see CheckerContext::isCLibraryFunction().
/// Note that functions whose declaration context is not a TU (e.g.
/// methods, functions in namespaces) are not accepted as C library
/// functions.
/// FIXME: If I understand it correctly, this discards calls where C++ code
/// refers a C library function through the namespace `std::` via headers
/// like <cstdlib>.
CLibrary,

/// Matches "simple" functions that are not methods. (Static methods are
/// methods.)
SimpleFunc,

/// Matches a C++ method (may be static, may be virtual, may be an
/// overloaded operator, a constructor or a destructor).
CXXMethod,

/// Match any CallEvent that is not an ObjCMethodCall.
/// FIXME: Previously this was the default behavior of CallDescription, but
/// its use should be replaced by a more specific mode almost everywhere.
Unspecified,

/// FIXME: Add support for ObjCMethodCall events (I'm not adding it because
/// I'm not familiar with Objective-C). Note that currently an early return
/// in `bool matches(const CallEvent &Call) const;` discards all
/// Objective-C method calls.
};

private:
friend class CallEvent;
using MaybeCount = std::optional<unsigned>;

Expand All @@ -50,20 +78,26 @@ class CallDescription {
std::vector<std::string> QualifiedName;
MaybeCount RequiredArgs;
MaybeCount RequiredParams;
int Flags;
Mode MatchAs;

public:
/// Constructs a CallDescription object.
///
/// @param MatchAs Specifies the kind of the call that should be matched.
///
/// @param QualifiedName The list of the name qualifiers of the function that
/// will be matched. The user is allowed to skip any of the qualifiers.
/// For example, {"std", "basic_string", "c_str"} would match both
/// std::basic_string<...>::c_str() and std::__1::basic_string<...>::c_str().
///
/// @param RequiredArgs The number of arguments that is expected to match a
/// call. Omit this parameter to match every occurrence of call with a given
/// name regardless the number of arguments.
CallDescription(CallDescriptionFlags Flags, ArrayRef<StringRef> QualifiedName,
/// @param RequiredArgs The expected number of arguments that are passed to
/// the function. Omit this parameter (or pass std::nullopt) to match every
/// occurrence without checking the argument count in the call.
///
/// @param RequiredParams The expected number of parameters in the function
/// definition that is called. Omit this parameter to match every occurrence
/// without checking the parameter count in the definition.
CallDescription(Mode MatchAs, ArrayRef<StringRef> QualifiedName,
MaybeCount RequiredArgs = std::nullopt,
MaybeCount RequiredParams = std::nullopt);

Expand Down Expand Up @@ -222,6 +256,10 @@ template <typename T> class CallDescriptionMap {
}
};

/// Enumerators of this enum class are used to construct CallDescription
/// objects; in that context the fully qualified name is needlessly verbose.
using CDM = CallDescription::Mode;

/// An immutable set of CallDescriptions.
/// Checkers can efficiently decide if a given CallEvent matches any
/// CallDescription in the set.
Expand Down
1 change: 0 additions & 1 deletion clang/lib/AST/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ add_clang_library(clangAST
InheritViz.cpp
Interp/ByteCodeEmitter.cpp
Interp/ByteCodeExprGen.cpp
Interp/ByteCodeGenError.cpp
Interp/ByteCodeStmtGen.cpp
Interp/Context.cpp
Interp/Descriptor.cpp
Expand Down
8 changes: 7 additions & 1 deletion clang/lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5042,7 +5042,13 @@ void RecordDecl::completeDefinition() {

// Layouts are dumped when computed, so if we are dumping for all complete
// types, we need to force usage to get types that wouldn't be used elsewhere.
if (Ctx.getLangOpts().DumpRecordLayoutsComplete)
//
// If the type is dependent, then we can't compute its layout because there
// is no way for us to know the size or alignment of a dependent type. Also
// ignore declarations marked as invalid since 'getASTRecordLayout()' asserts
// on that.
if (Ctx.getLangOpts().DumpRecordLayoutsComplete && !isDependentType() &&
!isInvalidDecl())
(void)Ctx.getASTRecordLayout(this);
}

Expand Down
6 changes: 1 addition & 5 deletions clang/lib/AST/Interp/ByteCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
//===----------------------------------------------------------------------===//

#include "ByteCodeEmitter.h"
#include "ByteCodeGenError.h"
#include "Context.h"
#include "Floating.h"
#include "IntegralAP.h"
Expand Down Expand Up @@ -302,10 +301,7 @@ bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &S
if (SI)
SrcMap.emplace_back(Code.size(), SI);

// The initializer list forces the expression to be evaluated
// for each argument in the variadic template, in order.
(void)std::initializer_list<int>{(emit(P, Code, Args, Success), 0)...};

(..., emit(P, Code, Args, Success));
return Success;
}

Expand Down
23 changes: 19 additions & 4 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

#include "ByteCodeExprGen.h"
#include "ByteCodeEmitter.h"
#include "ByteCodeGenError.h"
#include "ByteCodeStmtGen.h"
#include "Context.h"
#include "Floating.h"
Expand Down Expand Up @@ -2663,6 +2662,11 @@ bool ByteCodeExprGen<Emitter>::visitVarDecl(const VarDecl *VD) {
if (P.getGlobal(VD))
return true;

// Ignore external declarations. We will instead emit a dummy
// pointer when we see a DeclRefExpr for them.
if (VD->hasExternalStorage())
return true;

std::optional<unsigned> GlobalIndex = P.createGlobal(VD, Init);

if (!GlobalIndex)
Expand Down Expand Up @@ -2725,6 +2729,18 @@ bool ByteCodeExprGen<Emitter>::VisitBuiltinCallExpr(const CallExpr *E) {
if (!Func)
return false;

QualType ReturnType = E->getType();
std::optional<PrimType> ReturnT = classify(E);

// Non-primitive return type. Prepare storage.
if (!Initializing && !ReturnT && !ReturnType->isVoidType()) {
std::optional<unsigned> LocalIndex = allocateLocal(E, /*IsExtended=*/false);
if (!LocalIndex)
return false;
if (!this->emitGetPtrLocal(*LocalIndex, E))
return false;
}

if (!Func->isUnevaluatedBuiltin()) {
// Put arguments on the stack.
for (const auto *Arg : E->arguments()) {
Expand All @@ -2736,10 +2752,9 @@ bool ByteCodeExprGen<Emitter>::VisitBuiltinCallExpr(const CallExpr *E) {
if (!this->emitCallBI(Func, E, E))
return false;

QualType ReturnType = E->getCallReturnType(Ctx.getASTContext());
if (DiscardResult && !ReturnType->isVoidType()) {
PrimType T = classifyPrim(ReturnType);
return this->emitPop(T, E);
assert(ReturnT);
return this->emitPop(*ReturnT, E);
}

return true;
Expand Down
46 changes: 0 additions & 46 deletions clang/lib/AST/Interp/ByteCodeGenError.h

This file was deleted.

1 change: 0 additions & 1 deletion clang/lib/AST/Interp/ByteCodeStmtGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

#include "ByteCodeStmtGen.h"
#include "ByteCodeEmitter.h"
#include "ByteCodeGenError.h"
#include "Context.h"
#include "Function.h"
#include "PrimType.h"
Expand Down
12 changes: 0 additions & 12 deletions clang/lib/AST/Interp/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
#include "Context.h"
#include "ByteCodeEmitter.h"
#include "ByteCodeExprGen.h"
#include "ByteCodeGenError.h"
#include "ByteCodeStmtGen.h"
#include "EvalEmitter.h"
#include "Interp.h"
Expand Down Expand Up @@ -208,17 +207,6 @@ bool Context::Run(State &Parent, const Function *Func, APValue &Result) {
return false;
}

bool Context::Check(State &Parent, llvm::Expected<bool> &&Flag) {
if (Flag)
return *Flag;
handleAllErrors(Flag.takeError(), [&Parent](ByteCodeGenError &Err) {
Parent.FFDiag(Err.getRange().getBegin(),
diag::err_experimental_clang_interp_failed)
<< Err.getRange();
});
return false;
}

// TODO: Virtual bases?
const CXXMethodDecl *
Context::getOverridingFunction(const CXXRecordDecl *DynamicDecl,
Expand Down
3 changes: 0 additions & 3 deletions clang/lib/AST/Interp/Context.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,6 @@ class Context final {
/// Runs a function.
bool Run(State &Parent, const Function *Func, APValue &Result);

/// Checks a result from the interpreter.
bool Check(State &Parent, llvm::Expected<bool> &&R);

/// Current compilation context.
ASTContext &Ctx;
/// Interpreter stack, shared across invocations.
Expand Down
1 change: 0 additions & 1 deletion clang/lib/AST/Interp/EvalEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
//===----------------------------------------------------------------------===//

#include "EvalEmitter.h"
#include "ByteCodeGenError.h"
#include "Context.h"
#include "IntegralAP.h"
#include "Interp.h"
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1448,6 +1448,8 @@ template <PrimType Name, class T = typename PrimConv<Name>::T>
bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
const T &Value = S.Stk.pop<T>();
const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx);
if (Ptr.isUnknownSizeArray())
return false;
if (!CheckInit(S, OpPC, Ptr))
return false;
Ptr.initialize();
Expand All @@ -1460,6 +1462,8 @@ template <PrimType Name, class T = typename PrimConv<Name>::T>
bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
const T &Value = S.Stk.pop<T>();
const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx);
if (Ptr.isUnknownSizeArray())
return false;
if (!CheckInit(S, OpPC, Ptr))
return false;
Ptr.initialize();
Expand Down
39 changes: 32 additions & 7 deletions clang/lib/AST/Interp/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC,
if (!CheckLive(S, OpPC, A, AK_Read) || !CheckLive(S, OpPC, B, AK_Read))
return false;

if (A.isDummy() || B.isDummy())
return false;

assert(A.getFieldDesc()->isPrimitiveArray());
assert(B.getFieldDesc()->isPrimitiveArray());

Expand Down Expand Up @@ -460,9 +463,6 @@ static bool interp__builtin_popcount(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func,
const CallExpr *Call) {

Func->getDecl()->dump();

PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
APSInt Val = peekToAPSInt(S.Stk, ArgT);
pushInteger(S, Val.popcount(), Call->getType());
Expand Down Expand Up @@ -900,16 +900,32 @@ static bool interp__builtin_atomic_lock_free(InterpState &S, CodePtr OpPC,
return false;
}

/// __builtin_complex(Float A, float B);
static bool interp__builtin_complex(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func,
const CallExpr *Call) {
const Floating &Arg2 = S.Stk.peek<Floating>();
const Floating &Arg1 = S.Stk.peek<Floating>(align(primSize(PT_Float)) * 2);
Pointer &Result = S.Stk.peek<Pointer>(align(primSize(PT_Float)) * 2 +
align(primSize(PT_Ptr)));

Result.atIndex(0).deref<Floating>() = Arg1;
Result.atIndex(0).initialize();
Result.atIndex(1).deref<Floating>() = Arg2;
Result.atIndex(1).initialize();
Result.initialize();

return true;
}

bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
const CallExpr *Call) {
InterpFrame *Frame = S.Current;
APValue Dummy;

std::optional<PrimType> ReturnT = S.getContext().classify(Call);

// If classify failed, we assume void.
assert(ReturnT || Call->getType()->isVoidType());

switch (F->getBuiltinID()) {
case Builtin::BI__builtin_is_constant_evaluated:
S.Stk.push<Boolean>(Boolean::from(S.inConstantContext()));
Expand Down Expand Up @@ -1206,7 +1222,16 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
return false;
break;

case Builtin::BI__builtin_complex:
if (!interp__builtin_complex(S, OpPC, Frame, F, Call))
return false;
break;

default:
S.FFDiag(S.Current->getLocation(OpPC),
diag::note_invalid_subexpr_in_const_expr)
<< S.Current->getRange(OpPC);

return false;
}

Expand All @@ -1230,7 +1255,7 @@ bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
const RecordType *RT = CurrentType->getAs<RecordType>();
if (!RT)
return false;
RecordDecl *RD = RT->getDecl();
const RecordDecl *RD = RT->getDecl();
if (RD->isInvalidDecl())
return false;
const ASTRecordLayout &RL = S.getCtx().getASTRecordLayout(RD);
Expand Down
29 changes: 8 additions & 21 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17091,37 +17091,24 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
}
return Builder.CreateCall(CGM.getIntrinsic(ID), Ops, "");
}
// Rotate and insert under mask operation.
// __rldimi(rs, is, shift, mask)
// (rotl64(rs, shift) & mask) | (is & ~mask)
// __rlwimi(rs, is, shift, mask)
// (rotl(rs, shift) & mask) | (is & ~mask)
case PPC::BI__builtin_ppc_rldimi:
case PPC::BI__builtin_ppc_rlwimi: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
Value *Op1 = EmitScalarExpr(E->getArg(1));
Value *Op2 = EmitScalarExpr(E->getArg(2));
Value *Op3 = EmitScalarExpr(E->getArg(3));
llvm::Type *Ty = Op0->getType();
Function *F = CGM.getIntrinsic(Intrinsic::fshl, Ty);
if (BuiltinID == PPC::BI__builtin_ppc_rldimi)
Op2 = Builder.CreateZExt(Op2, Int64Ty);
Value *Shift = Builder.CreateCall(F, {Op0, Op0, Op2});
Value *X = Builder.CreateAnd(Shift, Op3);
Value *Y = Builder.CreateAnd(Op1, Builder.CreateNot(Op3));
return Builder.CreateOr(X, Y);
}
// Rotate and insert under mask operation.
// __rlwnm(rs, shift, mask)
// rotl(rs, shift) & mask
return Builder.CreateCall(
CGM.getIntrinsic(BuiltinID == PPC::BI__builtin_ppc_rldimi
? Intrinsic::ppc_rldimi
: Intrinsic::ppc_rlwimi),
{Op0, Op1, Op2, Op3});
}
case PPC::BI__builtin_ppc_rlwnm: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
Value *Op1 = EmitScalarExpr(E->getArg(1));
Value *Op2 = EmitScalarExpr(E->getArg(2));
llvm::Type *Ty = Op0->getType();
Function *F = CGM.getIntrinsic(Intrinsic::fshl, Ty);
Value *Shift = Builder.CreateCall(F, {Op0, Op0, Op1});
return Builder.CreateAnd(Shift, Op2);
return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::ppc_rlwnm),
{Op0, Op1, Op2});
}
case PPC::BI__builtin_ppc_poppar4:
case PPC::BI__builtin_ppc_poppar8: {
Expand Down
7 changes: 3 additions & 4 deletions clang/lib/Driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,11 +209,10 @@ Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple,

Name = std::string(llvm::sys::path::filename(ClangExecutable));
Dir = std::string(llvm::sys::path::parent_path(ClangExecutable));
InstalledDir = Dir; // Provide a sensible default installed dir.

if ((!SysRoot.empty()) && llvm::sys::path::is_relative(SysRoot)) {
// Prepend InstalledDir if SysRoot is relative
SmallString<128> P(InstalledDir);
SmallString<128> P(Dir);
llvm::sys::path::append(P, SysRoot);
SysRoot = std::string(P);
}
Expand Down Expand Up @@ -1337,7 +1336,7 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
if (const Arg *A = Args.getLastArg(options::OPT_target))
TargetTriple = A->getValue();
if (const Arg *A = Args.getLastArg(options::OPT_ccc_install_dir))
Dir = InstalledDir = A->getValue();
Dir = Dir = A->getValue();
for (const Arg *A : Args.filtered(options::OPT_B)) {
A->claim();
PrefixDirs.push_back(A->getValue(0));
Expand Down Expand Up @@ -2000,7 +1999,7 @@ void Driver::PrintVersion(const Compilation &C, raw_ostream &OS) const {
OS << '\n';

// Print out the install directory.
OS << "InstalledDir: " << InstalledDir << '\n';
OS << "InstalledDir: " << Dir << '\n';

// If configuration files were used, print their paths.
for (auto ConfigFile : ConfigFiles)
Expand Down
4 changes: 1 addition & 3 deletions clang/lib/Driver/ToolChains/AIX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,9 +342,7 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA,
/// AIX - AIX tool chain which can call as(1) and ld(1) directly.
AIX::AIX(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
: ToolChain(D, Triple, Args) {
getProgramPaths().push_back(getDriver().getInstalledDir());
if (getDriver().getInstalledDir() != getDriver().Dir)
getProgramPaths().push_back(getDriver().Dir);
getProgramPaths().push_back(getDriver().Dir);

ParseInlineAsmUsingAsmParser = Args.hasFlag(
options::OPT_fintegrated_as, options::OPT_fno_integrated_as, true);
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Driver/ToolChains/AMDGPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ RocmInstallationDetector::getInstallationPathCandidates() {
}

// Try to find relative to the compiler binary.
const char *InstallDir = D.getInstalledDir();
StringRef InstallDir = D.Dir;

// Check both a normal Unix prefix position of the clang binary, as well as
// the Windows-esque layout the ROCm packages use with the host architecture
Expand Down
4 changes: 1 addition & 3 deletions clang/lib/Driver/ToolChains/BareMetal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,7 @@ static bool findRISCVMultilibs(const Driver &D,
BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args)
: ToolChain(D, Triple, Args) {
getProgramPaths().push_back(getDriver().getInstalledDir());
if (getDriver().getInstalledDir() != getDriver().Dir)
getProgramPaths().push_back(getDriver().Dir);
getProgramPaths().push_back(getDriver().Dir);

findMultilibs(D, Triple, Args);
SmallString<128> SysRoot(computeSysRoot());
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1109,7 +1109,7 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
if ((getToolChain().getTriple().isNVPTX() ||
getToolChain().getTriple().isAMDGCN()) &&
C.getActiveOffloadKinds() == Action::OFK_None) {
SmallString<128> P(llvm::sys::path::parent_path(D.InstalledDir));
SmallString<128> P(llvm::sys::path::parent_path(D.Dir));
llvm::sys::path::append(P, "include");
llvm::sys::path::append(P, getToolChain().getTripleString());
CmdArgs.push_back("-internal-isystem");
Expand Down
36 changes: 7 additions & 29 deletions clang/lib/Driver/ToolChains/Darwin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -643,9 +643,8 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA,

// It seems that the 'e' option is completely ignored for dynamic executables
// (the default), and with static executables, the last one wins, as expected.
Args.addAllArgs(CmdArgs,
{options::OPT_d_Flag, options::OPT_s, options::OPT_t,
options::OPT_Z_Flag, options::OPT_u_Group, options::OPT_r});
Args.addAllArgs(CmdArgs, {options::OPT_d_Flag, options::OPT_s, options::OPT_t,
options::OPT_Z_Flag, options::OPT_u_Group});

// Forward -ObjC when either -ObjC or -ObjC++ is used, to force loading
// members of static archive libraries which implement Objective-C classes or
Expand Down Expand Up @@ -926,9 +925,7 @@ void darwin::VerifyDebug::ConstructJob(Compilation &C, const JobAction &JA,
MachO::MachO(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
: ToolChain(D, Triple, Args) {
// We expect 'as', 'ld', etc. to be adjacent to our install dir.
getProgramPaths().push_back(getDriver().getInstalledDir());
if (getDriver().getInstalledDir() != getDriver().Dir)
getProgramPaths().push_back(getDriver().Dir);
getProgramPaths().push_back(getDriver().Dir);
}

/// Darwin - Darwin tool chain for i386 and x86_64.
Expand Down Expand Up @@ -2517,25 +2514,19 @@ void DarwinClang::AddClangCXXStdlibIncludeArgs(
switch (GetCXXStdlibType(DriverArgs)) {
case ToolChain::CST_Libcxx: {
// On Darwin, libc++ can be installed in one of the following places:
// 1. Alongside the compiler in <install>/include/c++/v1
// 2. Alongside the compiler in <clang-executable-folder>/../include/c++/v1
// 3. In a SDK (or a custom sysroot) in <sysroot>/usr/include/c++/v1
// 1. Alongside the compiler in <clang-executable-folder>/../include/c++/v1
// 2. In a SDK (or a custom sysroot) in <sysroot>/usr/include/c++/v1
//
// The precedence of paths is as listed above, i.e. we take the first path
// that exists. Note that we never include libc++ twice -- we take the first
// path that exists and don't send the other paths to CC1 (otherwise
// include_next could break).
//
// Also note that in most cases, (1) and (2) are exactly the same path.
// Those two paths will differ only when the `clang` program being run
// is actually a symlink to the real executable.

// Check for (1)
// Get from '<install>/bin' to '<install>/include/c++/v1'.
// Note that InstallBin can be relative, so we use '..' instead of
// parent_path.
llvm::SmallString<128> InstallBin =
llvm::StringRef(getDriver().getInstalledDir()); // <install>/bin
llvm::SmallString<128> InstallBin(getDriver().Dir); // <install>/bin
llvm::sys::path::append(InstallBin, "..", "include", "c++", "v1");
if (getVFS().exists(InstallBin)) {
addSystemInclude(DriverArgs, CC1Args, InstallBin);
Expand All @@ -2545,20 +2536,7 @@ void DarwinClang::AddClangCXXStdlibIncludeArgs(
<< "\"\n";
}

// (2) Check for the folder where the executable is located, if different.
if (getDriver().getInstalledDir() != getDriver().Dir) {
InstallBin = llvm::StringRef(getDriver().Dir);
llvm::sys::path::append(InstallBin, "..", "include", "c++", "v1");
if (getVFS().exists(InstallBin)) {
addSystemInclude(DriverArgs, CC1Args, InstallBin);
return;
} else if (DriverArgs.hasArg(options::OPT_v)) {
llvm::errs() << "ignoring nonexistent directory \"" << InstallBin
<< "\"\n";
}
}

// Otherwise, check for (3)
// Otherwise, check for (2)
llvm::SmallString<128> SysrootUsr = Sysroot;
llvm::sys::path::append(SysrootUsr, "usr", "include", "c++", "v1");
if (getVFS().exists(SysrootUsr)) {
Expand Down
7 changes: 2 additions & 5 deletions clang/lib/Driver/ToolChains/DragonFly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}

Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
options::OPT_s, options::OPT_t, options::OPT_r});
options::OPT_s, options::OPT_t});
ToolChain.AddFilePathLibArgs(Args, CmdArgs);

AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
Expand Down Expand Up @@ -205,11 +205,8 @@ void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA,
DragonFly::DragonFly(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args)
: Generic_ELF(D, Triple, Args) {

// Path mangling to find libexec
getProgramPaths().push_back(getDriver().getInstalledDir());
if (getDriver().getInstalledDir() != getDriver().Dir)
getProgramPaths().push_back(getDriver().Dir);
getProgramPaths().push_back(getDriver().Dir);

getFilePaths().push_back(getDriver().Dir + "/../lib");
getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib"));
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Driver/ToolChains/FreeBSD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,8 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,

Args.AddAllArgs(CmdArgs, options::OPT_L);
ToolChain.AddFilePathLibArgs(Args, CmdArgs);
Args.addAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_s,
options::OPT_t, options::OPT_r});
Args.addAllArgs(CmdArgs,
{options::OPT_T_Group, options::OPT_s, options::OPT_t});

if (D.isUsingLTO()) {
assert(!Inputs.empty() && "Must have at least one input.");
Expand Down
4 changes: 1 addition & 3 deletions clang/lib/Driver/ToolChains/Fuchsia.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,9 +251,7 @@ void fuchsia::StaticLibTool::ConstructJob(Compilation &C, const JobAction &JA,
Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args)
: ToolChain(D, Triple, Args) {
getProgramPaths().push_back(getDriver().getInstalledDir());
if (getDriver().getInstalledDir() != D.Dir)
getProgramPaths().push_back(D.Dir);
getProgramPaths().push_back(getDriver().Dir);

if (!D.SysRoot.empty()) {
SmallString<128> P(D.SysRoot);
Expand Down
6 changes: 2 additions & 4 deletions clang/lib/Driver/ToolChains/Gnu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2285,7 +2285,7 @@ void Generic_GCC::GCCInstallationDetector::init(
}

// Then look for gcc installed alongside clang.
Prefixes.push_back(D.InstalledDir + "/..");
Prefixes.push_back(D.Dir + "/..");

// Next, look for prefix(es) that correspond to distribution-supplied gcc
// installations.
Expand Down Expand Up @@ -3054,9 +3054,7 @@ Generic_GCC::Generic_GCC(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args)
: ToolChain(D, Triple, Args), GCCInstallation(D),
CudaInstallation(D, Triple, Args), RocmInstallation(D, Triple, Args) {
getProgramPaths().push_back(getDriver().getInstalledDir());
if (getDriver().getInstalledDir() != getDriver().Dir)
getProgramPaths().push_back(getDriver().Dir);
getProgramPaths().push_back(getDriver().Dir);
}

Generic_GCC::~Generic_GCC() {}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Driver/ToolChains/Haiku.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ void haiku::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}

Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
options::OPT_s, options::OPT_t, options::OPT_r});
options::OPT_s, options::OPT_t});
ToolChain.AddFilePathLibArgs(Args, CmdArgs);

if (D.isUsingLTO()) {
Expand Down
15 changes: 6 additions & 9 deletions clang/lib/Driver/ToolChains/Hexagon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,7 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA,
const std::string MCpuSuffix = "/" + CpuVer.str();
const std::string MCpuG0Suffix = MCpuSuffix + "/G0";
const std::string RootDir =
HTC.getHexagonTargetDir(D.InstalledDir, D.PrefixDirs) + "/";
HTC.getHexagonTargetDir(D.Dir, D.PrefixDirs) + "/";
const std::string StartSubDir =
"hexagon/lib" + (UseG0 ? MCpuG0Suffix : MCpuSuffix);

Expand Down Expand Up @@ -569,8 +569,7 @@ void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args,
std::copy(D.PrefixDirs.begin(), D.PrefixDirs.end(),
std::back_inserter(RootDirs));

std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
D.PrefixDirs);
std::string TargetDir = getHexagonTargetDir(D.Dir, D.PrefixDirs);
if (!llvm::is_contained(RootDirs, TargetDir))
RootDirs.push_back(TargetDir);

Expand All @@ -597,8 +596,7 @@ void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args,
HexagonToolChain::HexagonToolChain(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args)
: Linux(D, Triple, Args) {
const std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
D.PrefixDirs);
const std::string TargetDir = getHexagonTargetDir(D.Dir, D.PrefixDirs);

// Note: Generic_GCC::Generic_GCC adds InstalledDir and getDriver().Dir to
// program paths
Expand Down Expand Up @@ -728,8 +726,7 @@ void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,

if (HasSysRoot)
return;
std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
D.PrefixDirs);
std::string TargetDir = getHexagonTargetDir(D.Dir, D.PrefixDirs);
addExternCSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include");
}

Expand All @@ -744,7 +741,7 @@ void HexagonToolChain::addLibCxxIncludePaths(
addLibStdCXXIncludePaths("/usr/include/c++/v1", "", "", DriverArgs,
CC1Args);
else {
std::string TargetDir = getHexagonTargetDir(D.InstalledDir, D.PrefixDirs);
std::string TargetDir = getHexagonTargetDir(D.Dir, D.PrefixDirs);
addLibStdCXXIncludePaths(TargetDir + "/hexagon/include/c++/v1", "", "",
DriverArgs, CC1Args);
}
Expand All @@ -753,7 +750,7 @@ void HexagonToolChain::addLibStdCxxIncludePaths(
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const {
const Driver &D = getDriver();
std::string TargetDir = getHexagonTargetDir(D.InstalledDir, D.PrefixDirs);
std::string TargetDir = getHexagonTargetDir(D.Dir, D.PrefixDirs);
addLibStdCXXIncludePaths(TargetDir + "/hexagon/include/c++", "", "",
DriverArgs, CC1Args);
}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Driver/ToolChains/Linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ std::string Linux::computeSysRoot() const {
if (getTriple().isAndroid()) {
// Android toolchains typically include a sysroot at ../sysroot relative to
// the clang binary.
const StringRef ClangDir = getDriver().getInstalledDir();
const StringRef ClangDir = getDriver().Dir;
std::string AndroidSysRootPath = (ClangDir + "/../sysroot").str();
if (getVFS().exists(AndroidSysRootPath))
return AndroidSysRootPath;
Expand Down
4 changes: 1 addition & 3 deletions clang/lib/Driver/ToolChains/MSVC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -423,9 +423,7 @@ MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args)
: ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args),
RocmInstallation(D, Triple, Args) {
getProgramPaths().push_back(getDriver().getInstalledDir());
if (getDriver().getInstalledDir() != getDriver().Dir)
getProgramPaths().push_back(getDriver().Dir);
getProgramPaths().push_back(getDriver().Dir);

std::optional<llvm::StringRef> VCToolsDir, VCToolsVersion;
if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsdir))
Expand Down
9 changes: 4 additions & 5 deletions clang/lib/Driver/ToolChains/MinGW.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ findClangRelativeSysroot(const Driver &D, const llvm::Triple &LiteralTriple,
Subdirs.back() += "-w64-mingw32";
Subdirs.emplace_back(T.getArchName());
Subdirs.back() += "-w64-mingw32ucrt";
StringRef ClangRoot = llvm::sys::path::parent_path(D.getInstalledDir());
StringRef ClangRoot = llvm::sys::path::parent_path(D.Dir);
StringRef Sep = llvm::sys::path::get_separator();
for (StringRef CandidateSubdir : Subdirs) {
if (llvm::sys::fs::is_directory(ClangRoot + Sep + CandidateSubdir)) {
Expand All @@ -487,10 +487,10 @@ toolchains::MinGW::MinGW(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args)
: ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args),
RocmInstallation(D, Triple, Args) {
getProgramPaths().push_back(getDriver().getInstalledDir());
getProgramPaths().push_back(getDriver().Dir);

std::string InstallBase =
std::string(llvm::sys::path::parent_path(getDriver().getInstalledDir()));
std::string(llvm::sys::path::parent_path(getDriver().Dir));
// The sequence for detecting a sysroot here should be kept in sync with
// the testTriple function below.
llvm::Triple LiteralTriple = getLiteralTriple(D, getTriple());
Expand Down Expand Up @@ -796,8 +796,7 @@ static bool testTriple(const Driver &D, const llvm::Triple &Triple,
if (D.SysRoot.size())
return true;
llvm::Triple LiteralTriple = getLiteralTriple(D, Triple);
std::string InstallBase =
std::string(llvm::sys::path::parent_path(D.getInstalledDir()));
std::string InstallBase = std::string(llvm::sys::path::parent_path(D.Dir));
if (llvm::ErrorOr<std::string> TargetSubdir =
findClangRelativeSysroot(D, LiteralTriple, Triple, SubdirName))
return true;
Expand Down
7 changes: 3 additions & 4 deletions clang/lib/Driver/ToolChains/MipsLinux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@ void MipsLLVMToolChain::AddClangSystemIncludeArgs(
const auto &Callback = Multilibs.includeDirsCallback();
if (Callback) {
for (const auto &Path : Callback(SelectedMultilibs.back()))
addExternCSystemIncludeIfExists(DriverArgs, CC1Args,
D.getInstalledDir() + Path);
addExternCSystemIncludeIfExists(DriverArgs, CC1Args, D.Dir + Path);
}
}

Expand All @@ -70,7 +69,7 @@ std::string MipsLLVMToolChain::computeSysRoot() const {
if (!getDriver().SysRoot.empty())
return getDriver().SysRoot + SelectedMultilibs.back().osSuffix();

const std::string InstalledDir(getDriver().getInstalledDir());
const std::string InstalledDir(getDriver().Dir);
std::string SysRootPath =
InstalledDir + "/../sysroot" + SelectedMultilibs.back().osSuffix();
if (llvm::sys::fs::exists(SysRootPath))
Expand All @@ -97,7 +96,7 @@ void MipsLLVMToolChain::addLibCxxIncludePaths(
llvm::opt::ArgStringList &CC1Args) const {
if (const auto &Callback = Multilibs.includeDirsCallback()) {
for (std::string Path : Callback(SelectedMultilibs.back())) {
Path = getDriver().getInstalledDir() + Path + "/c++/v1";
Path = getDriver().Dir + Path + "/c++/v1";
if (llvm::sys::fs::exists(Path)) {
addSystemInclude(DriverArgs, CC1Args, Path);
return;
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Driver/ToolChains/NetBSD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}

Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
options::OPT_s, options::OPT_t, options::OPT_r});
options::OPT_s, options::OPT_t});
ToolChain.AddFilePathLibArgs(Args, CmdArgs);

bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs);
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Driver/ToolChains/OHOS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ std::string OHOS::computeSysRoot() const {
std::string SysRoot =
!getDriver().SysRoot.empty()
? getDriver().SysRoot
: makePath({getDriver().getInstalledDir(), "..", "..", "sysroot"});
: makePath({getDriver().Dir, "..", "..", "sysroot"});
if (!llvm::sys::fs::exists(SysRoot))
return std::string();

Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Driver/ToolChains/OpenBSD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,8 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,

Args.AddAllArgs(CmdArgs, options::OPT_L);
ToolChain.AddFilePathLibArgs(Args, CmdArgs);
Args.addAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_s,
options::OPT_t, options::OPT_r});
Args.addAllArgs(CmdArgs,
{options::OPT_T_Group, options::OPT_s, options::OPT_t});

if (D.isUsingLTO()) {
assert(!Inputs.empty() && "Must have at least one input.");
Expand Down
5 changes: 2 additions & 3 deletions clang/lib/Driver/ToolChains/PS4CPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,9 +208,8 @@ void tools::PScpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("--lto=full");
}

Args.addAllArgs(CmdArgs,
{options::OPT_L, options::OPT_T_Group, options::OPT_s,
options::OPT_t, options::OPT_r});
Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
options::OPT_s, options::OPT_t});

if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
CmdArgs.push_back("--no-demangle");
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/Driver/ToolChains/Solaris.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,7 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA,

ToolChain.AddFilePathLibArgs(Args, CmdArgs);

Args.addAllArgs(CmdArgs,
{options::OPT_L, options::OPT_T_Group, options::OPT_r});
Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group});

bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs);
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Driver/ToolChains/WebAssembly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple,

assert(Triple.isArch32Bit() != Triple.isArch64Bit());

getProgramPaths().push_back(getDriver().getInstalledDir());
getProgramPaths().push_back(getDriver().Dir);

auto SysRoot = getDriver().SysRoot;
if (getTriple().getOS() == llvm::Triple::UnknownOS) {
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/Driver/ToolChains/ZOS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -325,8 +325,7 @@ void ZOS::AddClangCXXStdlibIncludeArgs(
switch (GetCXXStdlibType(DriverArgs)) {
case ToolChain::CST_Libcxx: {
// <install>/bin/../include/c++/v1
llvm::SmallString<128> InstallBin =
llvm::StringRef(getDriver().getInstalledDir());
llvm::SmallString<128> InstallBin(getDriver().Dir);
llvm::sys::path::append(InstallBin, "..", "include", "c++", "v1");
TryAddIncludeFromPath(InstallBin, DriverArgs, CC1Args);
break;
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Format/FormatToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -821,8 +821,8 @@ struct FormatToken {

/// Returns whether the token is the left square bracket of a C++
/// structured binding declaration.
bool isCppStructuredBinding(const FormatStyle &Style) const {
if (!Style.isCpp() || isNot(tok::l_square))
bool isCppStructuredBinding(bool IsCpp) const {
if (!IsCpp || isNot(tok::l_square))
return false;
const FormatToken *T = this;
do {
Expand Down
39 changes: 18 additions & 21 deletions clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ class AnnotatingParser {
const AdditionalKeywords &Keywords,
SmallVector<ScopeType> &Scopes)
: Style(Style), Line(Line), CurrentToken(Line.First), AutoFound(false),
Keywords(Keywords), Scopes(Scopes) {
IsCpp(Style.isCpp()), Keywords(Keywords), Scopes(Scopes) {
Contexts.push_back(Context(tok::unknown, 1, /*IsExpression=*/false));
resetTokenMetadata();
}
Expand Down Expand Up @@ -676,26 +676,25 @@ class AnnotatingParser {
// In C++, this can happen either in array of templates (foo<int>[10])
// or when array is a nested template type (unique_ptr<type1<type2>[]>).
bool CppArrayTemplates =
Style.isCpp() && Parent && Parent->is(TT_TemplateCloser) &&
IsCpp && Parent && Parent->is(TT_TemplateCloser) &&
(Contexts.back().CanBeExpression || Contexts.back().IsExpression ||
Contexts.back().ContextType == Context::TemplateArgument);

const bool IsInnerSquare = Contexts.back().InCpp11AttributeSpecifier;
const bool IsCpp11AttributeSpecifier =
isCppAttribute(Style.isCpp(), *Left) || IsInnerSquare;
isCppAttribute(IsCpp, *Left) || IsInnerSquare;

// Treat C# Attributes [STAThread] much like C++ attributes [[...]].
bool IsCSharpAttributeSpecifier =
isCSharpAttributeSpecifier(*Left) ||
Contexts.back().InCSharpAttributeSpecifier;

bool InsideInlineASM = Line.startsWith(tok::kw_asm);
bool IsCppStructuredBinding = Left->isCppStructuredBinding(Style);
bool IsCppStructuredBinding = Left->isCppStructuredBinding(IsCpp);
bool StartsObjCMethodExpr =
!IsCppStructuredBinding && !InsideInlineASM && !CppArrayTemplates &&
Style.isCpp() && !IsCpp11AttributeSpecifier &&
!IsCSharpAttributeSpecifier && Contexts.back().CanBeExpression &&
Left->isNot(TT_LambdaLSquare) &&
IsCpp && !IsCpp11AttributeSpecifier && !IsCSharpAttributeSpecifier &&
Contexts.back().CanBeExpression && Left->isNot(TT_LambdaLSquare) &&
!CurrentToken->isOneOf(tok::l_brace, tok::r_square) &&
(!Parent ||
Parent->isOneOf(tok::colon, tok::l_square, tok::l_paren,
Expand Down Expand Up @@ -723,7 +722,7 @@ class AnnotatingParser {
Contexts.back().ContextKind == tok::l_brace &&
Parent->isOneOf(tok::l_brace, tok::comma)) {
Left->setType(TT_JsComputedPropertyName);
} else if (Style.isCpp() && Contexts.back().ContextKind == tok::l_brace &&
} else if (IsCpp && Contexts.back().ContextKind == tok::l_brace &&
Parent && Parent->isOneOf(tok::l_brace, tok::comma)) {
Left->setType(TT_DesignatedInitializerLSquare);
} else if (IsCSharpAttributeSpecifier) {
Expand Down Expand Up @@ -1161,7 +1160,7 @@ class AnnotatingParser {
if (Previous->is(TT_JsTypeOptionalQuestion))
Previous = Previous->getPreviousNonComment();
if ((CurrentToken->is(tok::colon) && !Style.isTableGen() &&
(!Contexts.back().ColonIsDictLiteral || !Style.isCpp())) ||
(!Contexts.back().ColonIsDictLiteral || !IsCpp)) ||
Style.isProto()) {
OpeningBrace.setType(TT_DictLiteral);
if (Previous->Tok.getIdentifierInfo() ||
Expand Down Expand Up @@ -1230,7 +1229,7 @@ class AnnotatingParser {
}

bool consumeToken() {
if (Style.isCpp()) {
if (IsCpp) {
const auto *Prev = CurrentToken->getPreviousNonComment();
if (Prev && Prev->is(tok::r_square) && Prev->is(TT_AttributeSquare) &&
CurrentToken->isOneOf(tok::kw_if, tok::kw_switch, tok::kw_case,
Expand Down Expand Up @@ -1424,7 +1423,7 @@ class AnnotatingParser {
if (CurrentToken && CurrentToken->is(Keywords.kw_await))
next();
}
if (Style.isCpp() && CurrentToken && CurrentToken->is(tok::kw_co_await))
if (IsCpp && CurrentToken && CurrentToken->is(tok::kw_co_await))
next();
Contexts.back().ColonIsForRangeExpr = true;
if (!CurrentToken || CurrentToken->isNot(tok::l_paren))
Expand Down Expand Up @@ -2590,7 +2589,7 @@ class AnnotatingParser {
/// Determine whether '(' is starting a C++ cast.
bool lParenStartsCppCast(const FormatToken &Tok) {
// C-style casts are only used in C++.
if (!Style.isCpp())
if (!IsCpp)
return false;

FormatToken *LeftOfParens = Tok.getPreviousNonComment();
Expand All @@ -2611,10 +2610,8 @@ class AnnotatingParser {
/// Determine whether ')' is ending a cast.
bool rParenEndsCast(const FormatToken &Tok) {
// C-style casts are only used in C++, C# and Java.
if (!Style.isCSharp() && !Style.isCpp() &&
Style.Language != FormatStyle::LK_Java) {
if (!Style.isCSharp() && !IsCpp && Style.Language != FormatStyle::LK_Java)
return false;
}

// Empty parens aren't casts and there are no casts at the end of the line.
if (Tok.Previous == Tok.MatchingParen || !Tok.Next || !Tok.MatchingParen)
Expand Down Expand Up @@ -2691,7 +2688,7 @@ class AnnotatingParser {
if (Tok.Next->isOneOf(tok::kw_noexcept, tok::kw_volatile, tok::kw_const,
tok::kw_requires, tok::kw_throw, tok::arrow,
Keywords.kw_override, Keywords.kw_final) ||
isCppAttribute(Style.isCpp(), *Tok.Next)) {
isCppAttribute(IsCpp, *Tok.Next)) {
return false;
}

Expand Down Expand Up @@ -3012,6 +3009,7 @@ class AnnotatingParser {
AnnotatedLine &Line;
FormatToken *CurrentToken;
bool AutoFound;
bool IsCpp;
const AdditionalKeywords &Keywords;

SmallVector<ScopeType> &Scopes;
Expand Down Expand Up @@ -3559,7 +3557,7 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) {
ExpressionParser ExprParser(Style, Keywords, Line);
ExprParser.parse();

if (Style.isCpp()) {
if (IsCpp) {
auto *Tok = getFunctionName(Line);
if (Tok && ((!Scopes.empty() && Scopes.back() == ST_Class) ||
Line.endsWith(TT_FunctionLBrace) || isCtorOrDtorName(Tok))) {
Expand Down Expand Up @@ -3766,7 +3764,6 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const {
if (AlignArrayOfStructures)
calculateArrayInitializerColumnList(Line);

const bool IsCpp = Style.isCpp();
bool SeenName = false;
bool LineIsFunctionDeclaration = false;
FormatToken *ClosingParen = nullptr;
Expand All @@ -3779,7 +3776,7 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const {
AfterLastAttribute = Tok;
if (const bool IsCtorOrDtor = Tok->is(TT_CtorDtorDeclName);
IsCtorOrDtor ||
isFunctionDeclarationName(Style.isCpp(), *Tok, Line, ClosingParen)) {
isFunctionDeclarationName(IsCpp, *Tok, Line, ClosingParen)) {
if (!IsCtorOrDtor)
Tok->setFinalizedType(TT_FunctionDeclarationName);
LineIsFunctionDeclaration = true;
Expand Down Expand Up @@ -4717,7 +4714,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
if (Left.is(tok::star) && Right.is(tok::comment))
return true;

if (Style.isCpp()) {
if (IsCpp) {
if (Left.is(TT_OverloadedOperator) &&
Right.isOneOf(TT_TemplateOpener, TT_TemplateCloser)) {
return true;
Expand Down Expand Up @@ -5425,7 +5422,7 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
if (!Keywords.isVerilogBegin(Right) && Keywords.isVerilogEndOfLabel(Left))
return true;
} else if (Style.BreakAdjacentStringLiterals &&
(Style.isCpp() || Style.isProto() ||
(IsCpp || Style.isProto() ||
Style.Language == FormatStyle::LK_TableGen)) {
if (Left.isStringLiteral() && Right.isStringLiteral())
return true;
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Format/TokenAnnotator.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ class AnnotatedLine {
class TokenAnnotator {
public:
TokenAnnotator(const FormatStyle &Style, const AdditionalKeywords &Keywords)
: Style(Style), Keywords(Keywords) {}
: Style(Style), IsCpp(Style.isCpp()), Keywords(Keywords) {}

/// Adapts the indent levels of comment lines to the indent of the
/// subsequent line.
Expand Down Expand Up @@ -260,6 +260,8 @@ class TokenAnnotator {

const FormatStyle &Style;

bool IsCpp;

const AdditionalKeywords &Keywords;

SmallVector<ScopeType> Scopes;
Expand Down
43 changes: 21 additions & 22 deletions clang/lib/Format/UnwrappedLineParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,9 @@ UnwrappedLineParser::UnwrappedLineParser(
llvm::SpecificBumpPtrAllocator<FormatToken> &Allocator,
IdentifierTable &IdentTable)
: Line(new UnwrappedLine), MustBreakBeforeNextToken(false),
CurrentLines(&Lines), Style(Style), Keywords(Keywords),
CommentPragmasRegex(Style.CommentPragmas), Tokens(nullptr),
Callback(Callback), AllTokens(Tokens), PPBranchLevel(-1),
CurrentLines(&Lines), Style(Style), IsCpp(Style.isCpp()),
Keywords(Keywords), CommentPragmasRegex(Style.CommentPragmas),
Tokens(nullptr), Callback(Callback), AllTokens(Tokens), PPBranchLevel(-1),
IncludeGuard(Style.IndentPPDirectives == FormatStyle::PPDIS_None
? IG_Rejected
: IG_Inited),
Expand Down Expand Up @@ -572,8 +572,8 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) {
(Style.isJavaScript() &&
NextTok->isOneOf(Keywords.kw_of, Keywords.kw_in,
Keywords.kw_as));
ProbablyBracedList = ProbablyBracedList ||
(Style.isCpp() && NextTok->is(tok::l_paren));
ProbablyBracedList =
ProbablyBracedList || (IsCpp && NextTok->is(tok::l_paren));

// If there is a comma, semicolon or right paren after the closing
// brace, we assume this is a braced initializer list.
Expand Down Expand Up @@ -1428,7 +1428,7 @@ void UnwrappedLineParser::parseStructuralElement(
return;
}

if (Style.isCpp()) {
if (IsCpp) {
while (FormatTok->is(tok::l_square) && handleCppAttributes()) {
}
} else if (Style.isVerilog()) {
Expand Down Expand Up @@ -1602,7 +1602,7 @@ void UnwrappedLineParser::parseStructuralElement(
parseJavaScriptEs6ImportExport();
return;
}
if (Style.isCpp()) {
if (IsCpp) {
nextToken();
if (FormatTok->is(tok::kw_namespace)) {
parseNamespace();
Expand Down Expand Up @@ -1646,24 +1646,23 @@ void UnwrappedLineParser::parseStructuralElement(
addUnwrappedLine();
return;
}
if (Style.isCpp() && parseModuleImport())
if (IsCpp && parseModuleImport())
return;
}
if (Style.isCpp() &&
FormatTok->isOneOf(Keywords.kw_signals, Keywords.kw_qsignals,
Keywords.kw_slots, Keywords.kw_qslots)) {
if (IsCpp && FormatTok->isOneOf(Keywords.kw_signals, Keywords.kw_qsignals,
Keywords.kw_slots, Keywords.kw_qslots)) {
nextToken();
if (FormatTok->is(tok::colon)) {
nextToken();
addUnwrappedLine();
return;
}
}
if (Style.isCpp() && FormatTok->is(TT_StatementMacro)) {
if (IsCpp && FormatTok->is(TT_StatementMacro)) {
parseStatementMacro();
return;
}
if (Style.isCpp() && FormatTok->is(TT_NamespaceMacro)) {
if (IsCpp && FormatTok->is(TT_NamespaceMacro)) {
parseNamespace();
return;
}
Expand Down Expand Up @@ -1759,7 +1758,7 @@ void UnwrappedLineParser::parseStructuralElement(
}
break;
case tok::kw_requires: {
if (Style.isCpp()) {
if (IsCpp) {
bool ParsedClause = parseRequires();
if (ParsedClause)
return;
Expand All @@ -1780,7 +1779,7 @@ void UnwrappedLineParser::parseStructuralElement(
if (!parseEnum())
break;
// This only applies to C++ and Verilog.
if (!Style.isCpp() && !Style.isVerilog()) {
if (!IsCpp && !Style.isVerilog()) {
addUnwrappedLine();
return;
}
Expand Down Expand Up @@ -1848,7 +1847,7 @@ void UnwrappedLineParser::parseStructuralElement(
parseParens();
// Break the unwrapped line if a K&R C function definition has a parameter
// declaration.
if (OpeningBrace || !Style.isCpp() || !Previous || eof())
if (OpeningBrace || !IsCpp || !Previous || eof())
break;
if (isC78ParameterDecl(FormatTok,
Tokens->peekNextToken(/*SkipComment=*/true),
Expand Down Expand Up @@ -1977,13 +1976,13 @@ void UnwrappedLineParser::parseStructuralElement(
}
}

if (!Style.isCpp() && FormatTok->is(Keywords.kw_interface)) {
if (!IsCpp && FormatTok->is(Keywords.kw_interface)) {
if (parseStructLike())
return;
break;
}

if (Style.isCpp() && FormatTok->is(TT_StatementMacro)) {
if (IsCpp && FormatTok->is(TT_StatementMacro)) {
parseStatementMacro();
return;
}
Expand Down Expand Up @@ -2211,7 +2210,7 @@ bool UnwrappedLineParser::tryToParsePropertyAccessor() {

bool UnwrappedLineParser::tryToParseLambda() {
assert(FormatTok->is(tok::l_square));
if (!Style.isCpp()) {
if (!IsCpp) {
nextToken();
return false;
}
Expand Down Expand Up @@ -2340,7 +2339,7 @@ bool UnwrappedLineParser::tryToParseLambdaIntroducer() {
!Previous->isOneOf(tok::kw_return, tok::kw_co_await,
tok::kw_co_yield, tok::kw_co_return)) ||
Previous->closesScope())) ||
LeftSquare->isCppStructuredBinding(Style)) {
LeftSquare->isCppStructuredBinding(IsCpp)) {
return false;
}
if (FormatTok->is(tok::l_square) || tok::isLiteral(FormatTok->Tok.getKind()))
Expand Down Expand Up @@ -3153,7 +3152,7 @@ void UnwrappedLineParser::parseForOrWhileLoop(bool HasParens) {
// JS' for await ( ...
if (Style.isJavaScript() && FormatTok->is(Keywords.kw_await))
nextToken();
if (Style.isCpp() && FormatTok->is(tok::kw_co_await))
if (IsCpp && FormatTok->is(tok::kw_co_await))
nextToken();
if (HasParens && FormatTok->is(tok::l_paren)) {
// The type is only set for Verilog basically because we were afraid to
Expand Down Expand Up @@ -3737,7 +3736,7 @@ bool UnwrappedLineParser::parseEnum() {
nextToken();
// If there are two identifiers in a row, this is likely an elaborate
// return type. In Java, this can be "implements", etc.
if (Style.isCpp() && FormatTok->is(tok::identifier))
if (IsCpp && FormatTok->is(tok::identifier))
return false;
}
}
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Format/UnwrappedLineParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ class UnwrappedLineParser {
llvm::BitVector DeclarationScopeStack;

const FormatStyle &Style;
bool IsCpp;
const AdditionalKeywords &Keywords;

llvm::Regex CommentPragmasRegex;
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7928,7 +7928,7 @@ void Parser::ParseMisplacedBracketDeclarator(Declarator &D) {
// Adding back the bracket info to the end of the Declarator.
for (unsigned i = 0, e = TempDeclarator.getNumTypeObjects(); i < e; ++i) {
const DeclaratorChunk &Chunk = TempDeclarator.getTypeObject(i);
D.AddTypeInfo(Chunk, SourceLocation());
D.AddTypeInfo(Chunk, TempDeclarator.getAttributePool(), SourceLocation());
}

// The missing identifier would have been diagnosed in ParseDirectDeclarator.
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Sema/ParsedAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ void AttributePool::takePool(AttributePool &pool) {
pool.Attrs.clear();
}

void AttributePool::takeFrom(ParsedAttributesView &List, AttributePool &Pool) {
assert(&Pool != this && "AttributePool can't take attributes from itself");
llvm::for_each(List.AttrList, [&Pool](ParsedAttr *A) { Pool.remove(A); });
Attrs.insert(Attrs.end(), List.AttrList.begin(), List.AttrList.end());
}

namespace {

#include "clang/Sema/AttrParsedAttrImpl.inc"
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Sema/Scope.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ void Scope::setFlags(Scope *parent, unsigned flags) {
FnParent = parent->FnParent;
BlockParent = parent->BlockParent;
TemplateParamParent = parent->TemplateParamParent;
DeclParent = parent->DeclParent;
MSLastManglingParent = parent->MSLastManglingParent;
MSCurManglingNumber = getMSLastManglingNumber();
if ((Flags & (FnScope | ClassScope | BlockScope | TemplateParamScope |
Expand All @@ -52,6 +53,7 @@ void Scope::setFlags(Scope *parent, unsigned flags) {
PrototypeIndex = 0;
MSLastManglingParent = FnParent = BlockParent = nullptr;
TemplateParamParent = nullptr;
DeclParent = nullptr;
MSLastManglingNumber = 1;
MSCurManglingNumber = 1;
}
Expand All @@ -76,6 +78,7 @@ void Scope::setFlags(Scope *parent, unsigned flags) {
PrototypeDepth++;

if (flags & DeclScope) {
DeclParent = this;
if (flags & FunctionPrototypeScope)
; // Prototype scopes are uninteresting.
else if ((flags & ClassScope) && getParent()->isClassScope())
Expand Down
31 changes: 19 additions & 12 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6353,12 +6353,6 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
} else if (DiagnoseUnexpandedParameterPack(NameInfo, UPPC_DeclarationType))
return nullptr;

// The scope passed in may not be a decl scope. Zip up the scope tree until
// we find one that is.
while ((S->getFlags() & Scope::DeclScope) == 0 ||
(S->getFlags() & Scope::TemplateParamScope) != 0)
S = S->getParent();

DeclContext *DC = CurContext;
if (D.getCXXScopeSpec().isInvalid())
D.setInvalidType();
Expand Down Expand Up @@ -6486,12 +6480,22 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
RemoveUsingDecls(Previous);
}

if (Previous.isSingleResult() &&
Previous.getFoundDecl()->isTemplateParameter()) {
// Maybe we will complain about the shadowed template parameter.
if (!D.isInvalidType())
DiagnoseTemplateParameterShadow(D.getIdentifierLoc(),
Previous.getFoundDecl());
if (auto *TPD = Previous.getAsSingle<NamedDecl>();
TPD && TPD->isTemplateParameter()) {
// Older versions of clang allowed the names of function/variable templates
// to shadow the names of their template parameters. For the compatibility
// purposes we detect such cases and issue a default-to-error warning that
// can be disabled with -Wno-strict-primary-template-shadow.
if (!D.isInvalidType()) {
bool AllowForCompatibility = false;
if (Scope *DeclParent = S->getDeclParent();
Scope *TemplateParamParent = S->getTemplateParamParent()) {
AllowForCompatibility = DeclParent->Contains(*TemplateParamParent) &&
TemplateParamParent->isDeclScope(TPD);
}
DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), TPD,
AllowForCompatibility);
}

// Just pretend that we didn't see the previous declaration.
Previous.clear();
Expand All @@ -6515,6 +6519,9 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
if (getLangOpts().CPlusPlus)
CheckExtraCXXDefaultArguments(D);

/// Get the innermost enclosing declaration scope.
S = S->getDeclParent();

NamedDecl *New;

bool AddToScope = true;
Expand Down
13 changes: 4 additions & 9 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12203,10 +12203,8 @@ Decl *Sema::ActOnUsingDirective(Scope *S, SourceLocation UsingLoc,
assert(NamespcName && "Invalid NamespcName.");
assert(IdentLoc.isValid() && "Invalid NamespceName location.");

// This can only happen along a recovery path.
while (S->isTemplateParamScope())
S = S->getParent();
assert(S->getFlags() & Scope::DeclScope && "Invalid Scope.");
// Get the innermost enclosing declaration scope.
S = S->getDeclParent();

UsingDirectiveDecl *UDir = nullptr;
NestedNameSpecifier *Qualifier = nullptr;
Expand Down Expand Up @@ -13516,11 +13514,8 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, AccessSpecifier AS,
SourceLocation UsingLoc, UnqualifiedId &Name,
const ParsedAttributesView &AttrList,
TypeResult Type, Decl *DeclFromDeclSpec) {
// Skip up to the relevant declaration scope.
while (S->isTemplateParamScope())
S = S->getParent();
assert((S->getFlags() & Scope::DeclScope) &&
"got alias-declaration outside of declaration scope");
// Get the innermost enclosing declaration scope.
S = S->getDeclParent();

if (Type.isInvalid())
return nullptr;
Expand Down
Loading