Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
//===--- CrtpConstructorAccessibilityCheck.cpp - clang-tidy ---------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "CrtpConstructorAccessibilityCheck.h"
#include "../utils/LexerUtils.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"

using namespace clang::ast_matchers;

namespace clang::tidy::bugprone {

static bool hasPrivateConstructor(const CXXRecordDecl *RD) {
return llvm::any_of(RD->ctors(), [](const CXXConstructorDecl *Ctor) {
return Ctor->getAccess() == AS_private;
});
}

static bool isDerivedParameterBefriended(const CXXRecordDecl *CRTP,
const NamedDecl *Param) {
return llvm::any_of(CRTP->friends(), [&](const FriendDecl *Friend) {
const TypeSourceInfo *const FriendType = Friend->getFriendType();
if (!FriendType) {
return false;
}

const auto *const TTPT =
dyn_cast<TemplateTypeParmType>(FriendType->getType());

return TTPT && TTPT->getDecl() == Param;
});
}

static bool isDerivedClassBefriended(const CXXRecordDecl *CRTP,
const CXXRecordDecl *Derived) {
return llvm::any_of(CRTP->friends(), [&](const FriendDecl *Friend) {
const TypeSourceInfo *const FriendType = Friend->getFriendType();
if (!FriendType) {
return false;
}

return FriendType->getType()->getAsCXXRecordDecl() == Derived;
});
}

static const NamedDecl *
getDerivedParameter(const ClassTemplateSpecializationDecl *CRTP,
const CXXRecordDecl *Derived) {
size_t Idx = 0;
const bool AnyOf = llvm::any_of(
CRTP->getTemplateArgs().asArray(), [&](const TemplateArgument &Arg) {
++Idx;
return Arg.getKind() == TemplateArgument::Type &&
Arg.getAsType()->getAsCXXRecordDecl() == Derived;
});

return AnyOf ? CRTP->getSpecializedTemplate()
->getTemplateParameters()
->getParam(Idx - 1)
: nullptr;
}

static std::vector<FixItHint>
hintMakeCtorPrivate(const CXXConstructorDecl *Ctor,
const std::string &OriginalAccess) {
std::vector<FixItHint> Hints;

Hints.emplace_back(FixItHint::CreateInsertion(
Ctor->getBeginLoc().getLocWithOffset(-1), "private:\n"));

const ASTContext &ASTCtx = Ctor->getASTContext();
const SourceLocation CtorEndLoc =
Ctor->isExplicitlyDefaulted()
? utils::lexer::findNextTerminator(Ctor->getEndLoc(),
ASTCtx.getSourceManager(),
ASTCtx.getLangOpts())
: Ctor->getEndLoc();
Hints.emplace_back(FixItHint::CreateInsertion(
CtorEndLoc.getLocWithOffset(1), '\n' + OriginalAccess + ':' + '\n'));

return Hints;
}

void CrtpConstructorAccessibilityCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(
classTemplateSpecializationDecl(
decl().bind("crtp"),
hasAnyTemplateArgument(refersToType(recordType(hasDeclaration(
cxxRecordDecl(
isDerivedFrom(cxxRecordDecl(equalsBoundNode("crtp"))))
.bind("derived")))))),
this);
}

void CrtpConstructorAccessibilityCheck::check(
const MatchFinder::MatchResult &Result) {
const auto *CRTPInstantiation =
Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("crtp");
const auto *DerivedRecord = Result.Nodes.getNodeAs<CXXRecordDecl>("derived");
const CXXRecordDecl *CRTPDeclaration =
CRTPInstantiation->getSpecializedTemplate()->getTemplatedDecl();

if (!CRTPDeclaration->hasDefinition()) {
return;
}

const auto *DerivedTemplateParameter =
getDerivedParameter(CRTPInstantiation, DerivedRecord);

assert(DerivedTemplateParameter &&
"No template parameter corresponds to the derived class of the CRTP.");

bool NeedsFriend = !isDerivedParameterBefriended(CRTPDeclaration,
DerivedTemplateParameter) &&
!isDerivedClassBefriended(CRTPDeclaration, DerivedRecord);

const FixItHint HintFriend = FixItHint::CreateInsertion(
CRTPDeclaration->getBraceRange().getEnd(),
"friend " + DerivedTemplateParameter->getNameAsString() + ';' + '\n');

if (hasPrivateConstructor(CRTPDeclaration) && NeedsFriend) {
diag(CRTPDeclaration->getLocation(),
"the CRTP cannot be constructed from the derived class; consider "
"declaring the derived class as friend")
<< HintFriend;
}

auto WithFriendHintIfNeeded =
[&](const DiagnosticBuilder &Diag,
bool NeedsFriend) -> const DiagnosticBuilder & {
if (NeedsFriend)
Diag << HintFriend;

return Diag;
};

if (!CRTPDeclaration->hasUserDeclaredConstructor()) {
const bool IsStruct = CRTPDeclaration->isStruct();

WithFriendHintIfNeeded(
diag(CRTPDeclaration->getLocation(),
"the implicit default constructor of the CRTP is publicly "
"accessible; consider making it private%select{| and declaring "
"the derived class as friend}0")
<< NeedsFriend
<< FixItHint::CreateInsertion(
CRTPDeclaration->getBraceRange().getBegin().getLocWithOffset(
1),
(IsStruct ? "\nprivate:\n" : "\n") +
CRTPDeclaration->getNameAsString() + "() = default;\n" +
(IsStruct ? "public:\n" : "")),
NeedsFriend);
}

for (auto &&Ctor : CRTPDeclaration->ctors()) {
if (Ctor->getAccess() == AS_private)
continue;

const bool IsPublic = Ctor->getAccess() == AS_public;
const std::string Access = IsPublic ? "public" : "protected";

WithFriendHintIfNeeded(
diag(Ctor->getLocation(),
"%0 contructor allows the CRTP to be %select{inherited "
"from|constructed}1 as a regular template class; consider making "
"it private%select{| and declaring the derived class as friend}2")
<< Access << IsPublic << NeedsFriend
<< hintMakeCtorPrivate(Ctor, Access),
NeedsFriend);
}
}

bool CrtpConstructorAccessibilityCheck::isLanguageVersionSupported(
const LangOptions &LangOpts) const {
return LangOpts.CPlusPlus11;
}
} // namespace clang::tidy::bugprone
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//===--- CrtpConstructorAccessibilityCheck.h - clang-tidy -------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_CRTPCONSTRUCTORACCESSIBILITYCHECK_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_CRTPCONSTRUCTORACCESSIBILITYCHECK_H

#include "../ClangTidyCheck.h"

namespace clang::tidy::bugprone {

/// Detects error-prone Curiously Recurring Template Pattern usage, when the
/// CRTP can be constructed outside itself and the derived class.
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/crtp-constructor-accessibility.html
class CrtpConstructorAccessibilityCheck : public ClangTidyCheck {
public:
CrtpConstructorAccessibilityCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override;
};

} // namespace clang::tidy::bugprone

#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_CRTPCONSTRUCTORACCESSIBILITYCHECK_H
202 changes: 101 additions & 101 deletions clang-tools-extra/clang-tidy/bugprone/UnusedReturnValueCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,98 +33,98 @@ AST_MATCHER_P(FunctionDecl, isInstantiatedFrom, Matcher<FunctionDecl>,
UnusedReturnValueCheck::UnusedReturnValueCheck(llvm::StringRef Name,
ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
CheckedFunctions(Options.get("CheckedFunctions",
"::std::async;"
"::std::launder;"
"::std::remove;"
"::std::remove_if;"
"::std::unique;"
"::std::unique_ptr::release;"
"::std::basic_string::empty;"
"::std::vector::empty;"
"::std::back_inserter;"
"::std::distance;"
"::std::find;"
"::std::find_if;"
"::std::inserter;"
"::std::lower_bound;"
"::std::make_pair;"
"::std::map::count;"
"::std::map::find;"
"::std::map::lower_bound;"
"::std::multimap::equal_range;"
"::std::multimap::upper_bound;"
"::std::set::count;"
"::std::set::find;"
"::std::setfill;"
"::std::setprecision;"
"::std::setw;"
"::std::upper_bound;"
"::std::vector::at;"
// C standard library
"::bsearch;"
"::ferror;"
"::feof;"
"::isalnum;"
"::isalpha;"
"::isblank;"
"::iscntrl;"
"::isdigit;"
"::isgraph;"
"::islower;"
"::isprint;"
"::ispunct;"
"::isspace;"
"::isupper;"
"::iswalnum;"
"::iswprint;"
"::iswspace;"
"::isxdigit;"
"::memchr;"
"::memcmp;"
"::strcmp;"
"::strcoll;"
"::strncmp;"
"::strpbrk;"
"::strrchr;"
"::strspn;"
"::strstr;"
"::wcscmp;"
// POSIX
"::access;"
"::bind;"
"::connect;"
"::difftime;"
"::dlsym;"
"::fnmatch;"
"::getaddrinfo;"
"::getopt;"
"::htonl;"
"::htons;"
"::iconv_open;"
"::inet_addr;"
"::isascii;"
"::isatty;"
"::mmap;"
"::newlocale;"
"::openat;"
"::pathconf;"
"::pthread_equal;"
"::pthread_getspecific;"
"::pthread_mutex_trylock;"
"::readdir;"
"::readlink;"
"::recvmsg;"
"::regexec;"
"::scandir;"
"::semget;"
"::setjmp;"
"::shm_open;"
"::shmget;"
"::sigismember;"
"::strcasecmp;"
"::strsignal;"
"::ttyname")),
CheckedFunctions(utils::options::parseStringList(
Options.get("CheckedFunctions", "::std::async;"
"::std::launder;"
"::std::remove;"
"::std::remove_if;"
"::std::unique;"
"::std::unique_ptr::release;"
"::std::basic_string::empty;"
"::std::vector::empty;"
"::std::back_inserter;"
"::std::distance;"
"::std::find;"
"::std::find_if;"
"::std::inserter;"
"::std::lower_bound;"
"::std::make_pair;"
"::std::map::count;"
"::std::map::find;"
"::std::map::lower_bound;"
"::std::multimap::equal_range;"
"::std::multimap::upper_bound;"
"::std::set::count;"
"::std::set::find;"
"::std::setfill;"
"::std::setprecision;"
"::std::setw;"
"::std::upper_bound;"
"::std::vector::at;"
// C standard library
"::bsearch;"
"::ferror;"
"::feof;"
"::isalnum;"
"::isalpha;"
"::isblank;"
"::iscntrl;"
"::isdigit;"
"::isgraph;"
"::islower;"
"::isprint;"
"::ispunct;"
"::isspace;"
"::isupper;"
"::iswalnum;"
"::iswprint;"
"::iswspace;"
"::isxdigit;"
"::memchr;"
"::memcmp;"
"::strcmp;"
"::strcoll;"
"::strncmp;"
"::strpbrk;"
"::strrchr;"
"::strspn;"
"::strstr;"
"::wcscmp;"
// POSIX
"::access;"
"::bind;"
"::connect;"
"::difftime;"
"::dlsym;"
"::fnmatch;"
"::getaddrinfo;"
"::getopt;"
"::htonl;"
"::htons;"
"::iconv_open;"
"::inet_addr;"
"::isascii;"
"::isatty;"
"::mmap;"
"::newlocale;"
"::openat;"
"::pathconf;"
"::pthread_equal;"
"::pthread_getspecific;"
"::pthread_mutex_trylock;"
"::readdir;"
"::readlink;"
"::recvmsg;"
"::regexec;"
"::scandir;"
"::semget;"
"::setjmp;"
"::shm_open;"
"::shmget;"
"::sigismember;"
"::strcasecmp;"
"::strsignal;"
"::ttyname"))),
CheckedReturnTypes(utils::options::parseStringList(
Options.get("CheckedReturnTypes", "::std::error_code;"
"::std::error_condition;"
Expand All @@ -133,36 +133,36 @@ UnusedReturnValueCheck::UnusedReturnValueCheck(llvm::StringRef Name,
"::boost::system::error_code"))),
AllowCastToVoid(Options.get("AllowCastToVoid", false)) {}

UnusedReturnValueCheck::UnusedReturnValueCheck(llvm::StringRef Name,
ClangTidyContext *Context,
std::string CheckedFunctions)
UnusedReturnValueCheck::UnusedReturnValueCheck(
llvm::StringRef Name, ClangTidyContext *Context,
std::vector<StringRef> CheckedFunctions)
: UnusedReturnValueCheck(Name, Context, std::move(CheckedFunctions), {},
false) {}

UnusedReturnValueCheck::UnusedReturnValueCheck(
llvm::StringRef Name, ClangTidyContext *Context,
std::string CheckedFunctions, std::vector<StringRef> CheckedReturnTypes,
bool AllowCastToVoid)
std::vector<StringRef> CheckedFunctions,
std::vector<StringRef> CheckedReturnTypes, bool AllowCastToVoid)
: ClangTidyCheck(Name, Context),
CheckedFunctions(std::move(CheckedFunctions)),
CheckedReturnTypes(std::move(CheckedReturnTypes)),
AllowCastToVoid(AllowCastToVoid) {}

void UnusedReturnValueCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "CheckedFunctions", CheckedFunctions);
Options.store(Opts, "CheckedFunctions",
utils::options::serializeStringList(CheckedFunctions));
Options.store(Opts, "CheckedReturnTypes",
utils::options::serializeStringList(CheckedReturnTypes));
Options.store(Opts, "AllowCastToVoid", AllowCastToVoid);
}

void UnusedReturnValueCheck::registerMatchers(MatchFinder *Finder) {
auto FunVec = utils::options::parseStringList(CheckedFunctions);

auto MatchedDirectCallExpr =
expr(callExpr(callee(functionDecl(
// Don't match void overloads of checked functions.
unless(returns(voidType())),
anyOf(isInstantiatedFrom(hasAnyName(FunVec)),
anyOf(isInstantiatedFrom(matchers::matchesAnyListedName(
CheckedFunctions)),
returns(hasCanonicalType(hasDeclaration(
namedDecl(matchers::matchesAnyListedName(
CheckedReturnTypes)))))))))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ class UnusedReturnValueCheck : public ClangTidyCheck {
}

private:
std::string CheckedFunctions;
const std::vector<StringRef> CheckedFunctions;
const std::vector<StringRef> CheckedReturnTypes;

protected:
UnusedReturnValueCheck(StringRef Name, ClangTidyContext *Context,
std::string CheckedFunctions);
std::vector<StringRef> CheckedFunctions);
UnusedReturnValueCheck(StringRef Name, ClangTidyContext *Context,
std::string CheckedFunctions,
std::vector<StringRef> CheckedFunctions,
std::vector<StringRef> CheckedReturnTypes,
bool AllowCastToVoid);
bool AllowCastToVoid;
Expand Down
57 changes: 42 additions & 15 deletions clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,8 @@ void UseAfterMoveFinder::getReinits(
traverse(TK_AsIs, DeclRefMatcher),
unless(parmVarDecl(hasType(
references(qualType(isConstQualified())))))),
unless(callee(functionDecl(hasName("::std::move")))))))
unless(callee(functionDecl(
hasAnyName("::std::move", "::std::forward")))))))
.bind("reinit");

Stmts->clear();
Expand Down Expand Up @@ -359,24 +360,46 @@ void UseAfterMoveFinder::getReinits(
}
}

enum class MoveType {
Move, // std::move
Forward, // std::forward
};

static MoveType determineMoveType(const FunctionDecl *FuncDecl) {
if (FuncDecl->getName() == "move")
return MoveType::Move;
if (FuncDecl->getName() == "forward")
return MoveType::Forward;

llvm_unreachable("Invalid move type");
}

static void emitDiagnostic(const Expr *MovingCall, const DeclRefExpr *MoveArg,
const UseAfterMove &Use, ClangTidyCheck *Check,
ASTContext *Context) {
SourceLocation UseLoc = Use.DeclRef->getExprLoc();
SourceLocation MoveLoc = MovingCall->getExprLoc();
ASTContext *Context, MoveType Type) {
const SourceLocation UseLoc = Use.DeclRef->getExprLoc();
const SourceLocation MoveLoc = MovingCall->getExprLoc();

const bool IsMove = (Type == MoveType::Move);

Check->diag(UseLoc, "'%0' used after it was moved")
<< MoveArg->getDecl()->getName();
Check->diag(MoveLoc, "move occurred here", DiagnosticIDs::Note);
Check->diag(UseLoc, "'%0' used after it was %select{forwarded|moved}1")
<< MoveArg->getDecl()->getName() << IsMove;
Check->diag(MoveLoc, "%select{forward|move}0 occurred here",
DiagnosticIDs::Note)
<< IsMove;
if (Use.EvaluationOrderUndefined) {
Check->diag(UseLoc,
"the use and move are unsequenced, i.e. there is no guarantee "
"about the order in which they are evaluated",
DiagnosticIDs::Note);
Check->diag(
UseLoc,
"the use and %select{forward|move}0 are unsequenced, i.e. "
"there is no guarantee about the order in which they are evaluated",
DiagnosticIDs::Note)
<< IsMove;
} else if (UseLoc < MoveLoc || Use.DeclRef == MoveArg) {
Check->diag(UseLoc,
"the use happens in a later loop iteration than the move",
DiagnosticIDs::Note);
"the use happens in a later loop iteration than the "
"%select{forward|move}0",
DiagnosticIDs::Note)
<< IsMove;
}
}

Expand All @@ -388,7 +411,9 @@ void UseAfterMoveCheck::registerMatchers(MatchFinder *Finder) {
auto TryEmplaceMatcher =
cxxMemberCallExpr(callee(cxxMethodDecl(hasName("try_emplace"))));
auto CallMoveMatcher =
callExpr(argumentCountIs(1), callee(functionDecl(hasName("::std::move"))),
callExpr(argumentCountIs(1),
callee(functionDecl(hasAnyName("::std::move", "::std::forward"))
.bind("move-decl")),
hasArgument(0, declRefExpr().bind("arg")),
unless(inDecltypeOrTemplateArg()),
unless(hasParent(TryEmplaceMatcher)), expr().bind("call-move"),
Expand Down Expand Up @@ -436,6 +461,7 @@ void UseAfterMoveCheck::check(const MatchFinder::MatchResult &Result) {
const auto *CallMove = Result.Nodes.getNodeAs<CallExpr>("call-move");
const auto *MovingCall = Result.Nodes.getNodeAs<Expr>("moving-call");
const auto *Arg = Result.Nodes.getNodeAs<DeclRefExpr>("arg");
const auto *MoveDecl = Result.Nodes.getNodeAs<FunctionDecl>("move-decl");

if (!MovingCall || !MovingCall->getExprLoc().isValid())
MovingCall = CallMove;
Expand Down Expand Up @@ -470,7 +496,8 @@ void UseAfterMoveCheck::check(const MatchFinder::MatchResult &Result) {
UseAfterMoveFinder Finder(Result.Context);
UseAfterMove Use;
if (Finder.find(CodeBlock, MovingCall, Arg->getDecl(), &Use))
emitDiagnostic(MovingCall, Arg, Use, this, Result.Context);
emitDiagnostic(MovingCall, Arg, Use, this, Result.Context,
determineMoveType(MoveDecl));
}
}

Expand Down
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
4 changes: 4 additions & 0 deletions clang-tools-extra/clangd/refactor/Rename.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1062,6 +1062,10 @@ llvm::Expected<RenameResult> rename(const RenameInputs &RInputs) {
return makeError(ReasonToReject::AmbiguousSymbol);

const auto &RenameDecl = **DeclsUnderCursor.begin();
static constexpr trace::Metric RenameTriggerCounter(
"rename_trigger_count", trace::Metric::Counter, "decl_kind");
RenameTriggerCounter.record(1, RenameDecl.getDeclKindName());

std::string Placeholder = getName(RenameDecl);
auto Invalid = checkName(RenameDecl, RInputs.NewName, Placeholder);
if (Invalid)
Expand Down
14 changes: 14 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,12 @@ Improvements to clang-tidy
New checks
^^^^^^^^^^

- New :doc:`bugprone-crtp-constructor-accessibility
<clang-tidy/checks/bugprone/crtp-constructor-accessibility>` check.

Detects error-prone Curiously Recurring Template Pattern usage, when the CRTP
can be constructed outside itself and the derived class.

- New :doc:`modernize-use-designated-initializers
<clang-tidy/checks/modernize/use-designated-initializers>` check.

Expand Down Expand Up @@ -140,6 +146,14 @@ 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:`bugprone-use-after-move
<clang-tidy/checks/bugprone/use-after-move>` check to also handle
calls to ``std::forward``.

- Improved :doc:`cppcoreguidelines-missing-std-forward
<clang-tidy/checks/cppcoreguidelines/missing-std-forward>` check by no longer
giving false positives for deleted functions.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
.. title:: clang-tidy - bugprone-crtp-constructor-accessibility

bugprone-crtp-constructor-accessibility
=======================================

Detects error-prone Curiously Recurring Template Pattern usage, when the CRTP
can be constructed outside itself and the derived class.

The CRTP is an idiom, in which a class derives from a template class, where
itself is the template argument. It should be ensured that if a class is
intended to be a base class in this idiom, it can only be instantiated if
the derived class is it's template argument.

Example:

.. code-block:: c++

template <typename T> class CRTP {
private:
CRTP() = default;
friend T;
};

class Derived : CRTP<Derived> {};

Below can be seen some common mistakes that will allow the breaking of the
idiom.

If the constructor of a class intended to be used in a CRTP is public, then
it allows users to construct that class on its own.

Example:

.. code-block:: c++

template <typename T> class CRTP {
public:
CRTP() = default;
};

class Good : CRTP<Good> {};
Good GoodInstance;

CRTP<int> BadInstance;

If the constructor is protected, the possibility of an accidental instantiation
is prevented, however it can fade an error, when a different class is used as
the template parameter instead of the derived one.

Example:

.. code-block:: c++

template <typename T> class CRTP {
protected:
CRTP() = default;
};

class Good : CRTP<Good> {};
Good GoodInstance;

class Bad : CRTP<Good> {};
Bad BadInstance;

To ensure that no accidental instantiation happens, the best practice is to
make the constructor private and declare the derived class as friend. Note
that as a tradeoff, this also gives the derived class access to every other
private members of the CRTP.

Example:

.. code-block:: c++

template <typename T> class CRTP {
CRTP() = default;
friend T;
};

class Good : CRTP<Good> {};
Good GoodInstance;

class Bad : CRTP<Good> {};
Bad CompileTimeError;

CRTP<int> AlsoCompileTimeError;

Limitations:

* The check is not supported below C++11

* The check does not handle when the derived class is passed as a variadic
template argument

* Accessible functions that can construct the CRTP, like factory functions
are not checked

The check also suggests a fix-its in some cases.

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
Expand Up @@ -177,6 +177,18 @@ When analyzing the order in which moves, uses and reinitializations happen (see
section `Unsequenced moves, uses, and reinitializations`_), the move is assumed
to occur in whichever function the result of the ``std::move`` is passed to.

The check also handles perfect-forwarding with ``std::forward`` so the
following code will also trigger a use-after-move warning.

.. code-block:: c++

void consume(int);

void f(int&& i) {
consume(std::forward<int>(i));
consume(std::forward<int>(i)); // use-after-move
}

Use
---

Expand Down
1 change: 1 addition & 0 deletions clang-tools-extra/docs/clang-tidy/checks/list.rst
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ Clang-Tidy Checks
:doc:`bugprone-chained-comparison <bugprone/chained-comparison>`,
:doc:`bugprone-compare-pointer-to-member-virtual-function <bugprone/compare-pointer-to-member-virtual-function>`,
:doc:`bugprone-copy-constructor-init <bugprone/copy-constructor-init>`, "Yes"
:doc:`bugprone-crtp-constructor-accessibility <bugprone/crtp-constructor-accessibility>`, "Yes"
:doc:`bugprone-dangling-handle <bugprone/dangling-handle>`,
:doc:`bugprone-dynamic-static-initializers <bugprone/dynamic-static-initializers>`,
:doc:`bugprone-easily-swappable-parameters <bugprone/easily-swappable-parameters>`,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
// RUN: %check_clang_tidy -std=c++11-or-later %s bugprone-crtp-constructor-accessibility %t -- -- -fno-delayed-template-parsing

namespace class_implicit_ctor {
template <typename T>
class CRTP {};
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: the implicit default constructor of the CRTP is publicly accessible; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: CRTP() = default;
// CHECK-FIXES: friend T;

class A : CRTP<A> {};
} // namespace class_implicit_ctor

namespace class_unconstructible {
template <typename T>
class CRTP {
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: the CRTP cannot be constructed from the derived class; consider declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: friend T;
CRTP() = default;
};

class A : CRTP<A> {};
} // namespace class_unconstructible

namespace class_public_default_ctor {
template <typename T>
class CRTP {
public:
CRTP() = default;
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: public contructor allows the CRTP to be constructed as a regular template class; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: private:{{[[:space:]]*}}CRTP() = default;{{[[:space:]]*}}public:
// CHECK-FIXES: friend T;
};

class A : CRTP<A> {};
} // namespace class_public_default_ctor

namespace class_public_user_provided_ctor {
template <typename T>
class CRTP {
public:
CRTP(int) {}
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: public contructor allows the CRTP to be constructed as a regular template class; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: private:{{[[:space:]]*}}CRTP(int) {}{{[[:space:]]*}}public:
// CHECK-FIXES: friend T;
};

class A : CRTP<A> {};
} // namespace class_public_user_provided_ctor

namespace class_public_multiple_user_provided_ctors {
template <typename T>
class CRTP {
public:
CRTP(int) {}
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: public contructor allows the CRTP to be constructed as a regular template class; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: private:{{[[:space:]]*}}CRTP(int) {}{{[[:space:]]*}}public:
CRTP(float) {}
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: public contructor allows the CRTP to be constructed as a regular template class; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: private:{{[[:space:]]*}}CRTP(float) {}{{[[:space:]]*}}public:

// CHECK-FIXES: friend T;
// CHECK-FIXES: friend T;
};

class A : CRTP<A> {};
} // namespace class_public_multiple_user_provided_ctors

namespace class_protected_ctors {
template <typename T>
class CRTP {
protected:
CRTP(int) {}
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: protected contructor allows the CRTP to be inherited from as a regular template class; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: private:{{[[:space:]]*}}CRTP(int) {}{{[[:space:]]*}}protected:
CRTP() = default;
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: protected contructor allows the CRTP to be inherited from as a regular template class; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: private:{{[[:space:]]*}}CRTP() = default;{{[[:space:]]*}}protected:
CRTP(float) {}
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: protected contructor allows the CRTP to be inherited from as a regular template class; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: private:{{[[:space:]]*}}CRTP(float) {}{{[[:space:]]*}}protected:

// CHECK-FIXES: friend T;
// CHECK-FIXES: friend T;
// CHECK-FIXES: friend T;
};

class A : CRTP<A> {};
} // namespace class_protected_ctors

namespace struct_implicit_ctor {
template <typename T>
struct CRTP {};
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: the implicit default constructor of the CRTP is publicly accessible; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: private:{{[[:space:]]*}}CRTP() = default;{{[[:space:]]*}}public:
// CHECK-FIXES: friend T;

class A : CRTP<A> {};
} // namespace struct_implicit_ctor

namespace struct_default_ctor {
template <typename T>
struct CRTP {
CRTP() = default;
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: public contructor allows the CRTP to be constructed as a regular template class; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: private:{{[[:space:]]*}}CRTP() = default;{{[[:space:]]*}}public:
// CHECK-FIXES: friend T;
};

class A : CRTP<A> {};
} // namespace struct_default_ctor

namespace same_class_multiple_crtps {
template <typename T>
struct CRTP {};
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: the implicit default constructor of the CRTP is publicly accessible; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: private:{{[[:space:]]*}}CRTP() = default;{{[[:space:]]*}}public:
// CHECK-FIXES: friend T;

template <typename T>
struct CRTP2 {};
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: the implicit default constructor of the CRTP is publicly accessible; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: private:{{[[:space:]]*}}CRTP2() = default;{{[[:space:]]*}}public:
// CHECK-FIXES: friend T;

class A : CRTP<A>, CRTP2<A> {};
} // namespace same_class_multiple_crtps

namespace same_crtp_multiple_classes {
template <typename T>
class CRTP {
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: the CRTP cannot be constructed from the derived class; consider declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: friend T;
CRTP() = default;
};

class A : CRTP<A> {};
class B : CRTP<B> {};
} // namespace same_crtp_multiple_classes

namespace crtp_template {
template <typename T, typename U>
class CRTP {
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: the CRTP cannot be constructed from the derived class; consider declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: friend U;
CRTP() = default;
};

class A : CRTP<int, A> {};
} // namespace crtp_template

namespace crtp_template2 {
template <typename T, typename U>
class CRTP {
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: the CRTP cannot be constructed from the derived class; consider declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: friend T;
CRTP() = default;
};

class A : CRTP<A, A> {};
} // namespace crtp_template2

namespace template_derived {
template <typename T>
class CRTP {};
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: the implicit default constructor of the CRTP is publicly accessible; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: CRTP() = default;
// CHECK-FIXES: friend T;

template<typename T>
class A : CRTP<A<T>> {};

// FIXME: Ideally the warning should be triggered without instantiation.
void foo() {
A<int> A;
(void) A;
}
} // namespace template_derived

namespace template_derived_explicit_specialization {
template <typename T>
class CRTP {};
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: the implicit default constructor of the CRTP is publicly accessible; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: CRTP() = default;
// CHECK-FIXES: friend T;

template<typename T>
class A : CRTP<A<T>> {};

template<>
class A<int> : CRTP<A<int>> {};
} // namespace template_derived_explicit_specialization

namespace explicit_derived_friend {
class A;

template <typename T>
class CRTP {
CRTP() = default;
friend A;
};

class A : CRTP<A> {};
} // namespace explicit_derived_friend

namespace explicit_derived_friend_multiple {
class A;

template <typename T>
class CRTP {
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: the CRTP cannot be constructed from the derived class; consider declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: friend T;
CRTP() = default;
friend A;
};

class A : CRTP<A> {};
class B : CRTP<B> {};
} // namespace explicit_derived_friend_multiple

namespace no_need_for_friend {
class A;

template <typename T>
class CRTP {
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: the implicit default constructor of the CRTP is publicly accessible; consider making it private [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: CRTP() = default;
friend A;
};

class A : CRTP<A> {};
} // namespace no_need_for_friend

namespace no_warning {
template <typename T>
class CRTP
{
CRTP() = default;
friend T;
};

class A : CRTP<A> {};
} // namespace no_warning

namespace no_warning_unsupported {
template<typename... Types>
class CRTP
{};

class A : CRTP<A> {};

void foo() {
A A;
(void) A;
}
} // namespace no_warning_unsupported
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
Expand Up @@ -111,6 +111,18 @@ constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t) noexcept {
return static_cast<typename remove_reference<_Tp>::type &&>(__t);
}

template <class _Tp>
constexpr _Tp&&
forward(typename std::remove_reference<_Tp>::type& __t) noexcept {
return static_cast<_Tp&&>(__t);
}

template <class _Tp>
constexpr _Tp&&
forward(typename std::remove_reference<_Tp>::type&& __t) noexcept {
return static_cast<_Tp&&>(__t);
}

} // namespace std

class A {
Expand Down Expand Up @@ -1525,3 +1537,28 @@ class PR38187 {
private:
std::string val_;
};

namespace issue82023
{

struct S {
S();
S(S&&);
};

void consume(S s);

template <typename T>
void forward(T&& t) {
consume(std::forward<T>(t));
consume(std::forward<T>(t));
// CHECK-NOTES: [[@LINE-1]]:27: warning: 't' used after it was forwarded
// CHECK-NOTES: [[@LINE-3]]:11: note: forward occurred here
}

void create() {
S s;
forward(std::move(s));
}

} // namespace issue82023
20 changes: 10 additions & 10 deletions clang/docs/ClangFormatStyleOptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -318,9 +318,9 @@ the configuration (without a prefix: ``Auto``).

.. code-block:: c++

AlignConsecutiveMacros: AcrossEmptyLines
AlignConsecutiveAssignments: AcrossEmptyLines

AlignConsecutiveMacros:
AlignConsecutiveAssignments:
Enabled: true
AcrossEmptyLines: true
AcrossComments: false
Expand Down Expand Up @@ -460,9 +460,9 @@ the configuration (without a prefix: ``Auto``).

.. code-block:: c++

AlignConsecutiveMacros: AcrossEmptyLines
AlignConsecutiveBitFields: AcrossEmptyLines

AlignConsecutiveMacros:
AlignConsecutiveBitFields:
Enabled: true
AcrossEmptyLines: true
AcrossComments: false
Expand Down Expand Up @@ -602,9 +602,9 @@ the configuration (without a prefix: ``Auto``).

.. code-block:: c++

AlignConsecutiveMacros: AcrossEmptyLines
AlignConsecutiveDeclarations: AcrossEmptyLines

AlignConsecutiveMacros:
AlignConsecutiveDeclarations:
Enabled: true
AcrossEmptyLines: true
AcrossComments: false
Expand Down Expand Up @@ -983,9 +983,9 @@ the configuration (without a prefix: ``Auto``).

.. code-block:: c++

AlignConsecutiveMacros: AcrossEmptyLines
AlignConsecutiveTableGenCondOperatorColons: AcrossEmptyLines

AlignConsecutiveMacros:
AlignConsecutiveTableGenCondOperatorColons:
Enabled: true
AcrossEmptyLines: true
AcrossComments: false
Expand Down Expand Up @@ -1123,9 +1123,9 @@ the configuration (without a prefix: ``Auto``).

.. code-block:: c++

AlignConsecutiveMacros: AcrossEmptyLines
AlignConsecutiveTableGenDefinitionColons: AcrossEmptyLines

AlignConsecutiveMacros:
AlignConsecutiveTableGenDefinitionColons:
Enabled: true
AcrossEmptyLines: true
AcrossComments: false
Expand Down
13 changes: 12 additions & 1 deletion clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ Improvements to Clang's diagnostics
- The ``-Wshorten-64-to-32`` diagnostic is now grouped under ``-Wimplicit-int-conversion`` instead
of ``-Wconversion``. Fixes #GH69444.

- Clang now uses thousand separators when printing large numbers in integer overflow diagnostics.
Fixes #GH80939.

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

- Added diagnostics for C11 keywords being incompatible with language standards
Expand Down Expand Up @@ -265,6 +268,8 @@ Bug Fixes to C++ Support
- 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.
- Fix parsing of abominable function types inside type traits.
Fixes (`#77585 <https://github.com/llvm/llvm-project/issues/77585>`_)
- 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. Partially fixes
Expand Down Expand Up @@ -295,7 +300,13 @@ Bug Fixes to C++ Support
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 (#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).
- Fix evaluation of some immediate calls in default arguments.
Fixes (#GH80630)
- Fix a crash when an explicit template argument list is used with a name for which lookup
finds a non-template function and a dependent using declarator.

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
1 change: 1 addition & 0 deletions clang/docs/tools/dump_format_style.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ def __str__(self):
s += indent(
"\n\nNested configuration flags:\n\n%s\n" % self.nested_struct, 2
)
s = s.replace("<option-name>", self.name)
return s


Expand Down
80 changes: 52 additions & 28 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,17 @@ class FPMathTemplate : Template<["float", "double", "long double"],
["f", "", "l"]>;

class FPMathWithF16Template :
Template<["float", "double", "long double", "__fp16", "__float128"],
["f", "", "l", "f16", "f128"]>;
Template<["float", "double", "long double", "__fp16"],
["f", "", "l", "f16"]>;

class FPMathWithF16F128Template :
Template<["float", "double", "long double", "__fp16", "__float128"],
["f", "", "l", "f16", "f128"]>;

class FPMathWithF128Template :
Template<["float", "double", "long double", "__float128"],
["f", "", "l", "f128"]>;

class F16F128MathTemplate : Template<["__fp16", "__float128"],
["f16", "f128"]>;

Expand Down Expand Up @@ -253,18 +257,30 @@ def FrexpF16F128 : F16F128MathTemplate, Builtin {
let Prototype = "T(T, int*)";
}

def HugeVal : Builtin, FPMathWithF16F128Template {
def HugeVal : Builtin, FPMathWithF128Template {
let Spellings = ["__builtin_huge_val"];
let Attributes = [NoThrow, Const, Constexpr];
let Prototype = "T()";
}

def Inf : Builtin, FPMathWithF16F128Template {
def HugeValF16 : Builtin {
let Spellings = ["__builtin_huge_valf16"];
let Attributes = [NoThrow, Const, Constexpr];
let Prototype = "_Float16()";
}

def Inf : Builtin, FPMathWithF128Template {
let Spellings = ["__builtin_inf"];
let Attributes = [NoThrow, Const, Constexpr];
let Prototype = "T()";
}

def InfF16 : Builtin {
let Spellings = ["__builtin_inff16"];
let Attributes = [NoThrow, Const, Constexpr];
let Prototype = "_Float16()";
}

def LdexpF16F128 : F16F128MathTemplate, Builtin {
let Spellings = ["__builtin_ldexp"];
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions];
Expand Down Expand Up @@ -1550,7 +1566,7 @@ def SyncBoolCompareAndSwap : Builtin {
def SyncBoolCompareAndSwapN : Builtin, SyncBuiltinsTemplate {
let Spellings = ["__sync_bool_compare_and_swap_"];
let Attributes = [CustomTypeChecking, NoThrow];
let Prototype = "T(T volatile*, T, ...)";
let Prototype = "bool(T volatile*, T, T, ...)";
}

def SyncValCompareAndSwap : Builtin {
Expand All @@ -1562,7 +1578,7 @@ def SyncValCompareAndSwap : Builtin {
def SynLockValCompareAndSwapN : Builtin, SyncBuiltinsTemplate {
let Spellings = ["__sync_val_compare_and_swap_"];
let Attributes = [CustomTypeChecking, NoThrow];
let Prototype = "T(T volatile*, T, ...)";
let Prototype = "T(T volatile*, T, T, ...)";
}

def SyncLockTestAndSet : Builtin {
Expand All @@ -1577,16 +1593,16 @@ def SynLockLockTestAndSetN : Builtin, SyncBuiltinsTemplate {
let Prototype = "T(T volatile*, T, ...)";
}

def SyncLockReleaseN : Builtin {
def SyncLockRelease : Builtin {
let Spellings = ["__sync_lock_release"];
let Attributes = [CustomTypeChecking];
let Prototype = "void(...)";
}

def SynLockReleaseN : Builtin, SyncBuiltinsTemplate {
def SyncLockReleaseN : Builtin, SyncBuiltinsTemplate {
let Spellings = ["__sync_lock_release_"];
let Attributes = [CustomTypeChecking, NoThrow];
let Prototype = "T(T volatile*, T, ...)";
let Prototype = "void(T volatile*, ...)";
}

def SyncSwap : Builtin {
Expand Down Expand Up @@ -2569,6 +2585,13 @@ def Abort : LibBuiltin<"stdlib.h"> {
let AddBuiltinPrefixedAlias = 1;
}

def Abs : IntMathTemplate, LibBuiltin<"stdlib.h"> {
let Spellings = ["abs"];
let Attributes = [NoThrow, Const];
let Prototype = "T(T)";
let AddBuiltinPrefixedAlias = 1;
}

def Calloc : LibBuiltin<"stdlib.h"> {
let Spellings = ["calloc"];
let Prototype = "void*(size_t, size_t)";
Expand Down Expand Up @@ -3085,38 +3108,38 @@ def MemAlign : GNULibBuiltin<"malloc.h"> {

// POSIX string.h

def MemcCpy : GNULibBuiltin<"stdlib.h"> {
def MemcCpy : GNULibBuiltin<"string.h"> {
let Spellings = ["memccpy"];
let Prototype = "void*(void*, void const*, int, size_t)";
}

def MempCpy : GNULibBuiltin<"stdlib.h"> {
def MempCpy : GNULibBuiltin<"string.h"> {
let Spellings = ["mempcpy"];
let Prototype = "void*(void*, void const*, size_t)";
}

def StpCpy : GNULibBuiltin<"stdlib.h"> {
def StpCpy : GNULibBuiltin<"string.h"> {
let Spellings = ["stpcpy"];
let Attributes = [NoThrow];
let Prototype = "char*(char*, char const*)";
let AddBuiltinPrefixedAlias = 1;
}

def StpnCpy : GNULibBuiltin<"stdlib.h"> {
def StpnCpy : GNULibBuiltin<"string.h"> {
let Spellings = ["stpncpy"];
let Attributes = [NoThrow];
let Prototype = "char*(char*, char const*, size_t)";
let AddBuiltinPrefixedAlias = 1;
}

def StrDup : GNULibBuiltin<"stdlib.h"> {
def StrDup : GNULibBuiltin<"string.h"> {
let Spellings = ["strdup"];
let Attributes = [NoThrow];
let Prototype = "char*(char const*)";
let AddBuiltinPrefixedAlias = 1;
}

def StrnDup : GNULibBuiltin<"stdlib.h"> {
def StrnDup : GNULibBuiltin<"string.h"> {
let Spellings = ["strndup"];
let Attributes = [NoThrow];
let Prototype = "char*(char const*, size_t)";
Expand Down Expand Up @@ -3286,22 +3309,22 @@ def ObjcEnumerationMutation : ObjCLibBuiltin<"objc/runtime.h"> {
let Prototype = "void(id)";
}

def ObjcReadWeak : ObjCLibBuiltin<"objc/message.h"> {
def ObjcReadWeak : ObjCLibBuiltin<"objc/objc-auto.h"> {
let Spellings = ["objc_read_weak"];
let Prototype = "id(id*)";
}

def ObjcAssignWeak : ObjCLibBuiltin<"objc/message.h"> {
def ObjcAssignWeak : ObjCLibBuiltin<"objc/objc-auto.h"> {
let Spellings = ["objc_assign_weak"];
let Prototype = "id(id, id*)";
}

def ObjcAssignIvar : ObjCLibBuiltin<"objc/message.h"> {
def ObjcAssignIvar : ObjCLibBuiltin<"objc/objc-auto.h"> {
let Spellings = ["objc_assign_ivar"];
let Prototype = "id(id, id, ptrdiff_t)";
}

def ObjcAssignGlobal : ObjCLibBuiltin<"objc/message.h"> {
def ObjcAssignGlobal : ObjCLibBuiltin<"objc/objc-auto.h"> {
let Spellings = ["objc_assign_global"];
let Prototype = "id(id, id*)";
}
Expand Down Expand Up @@ -3371,13 +3394,6 @@ def Atan2 : FPMathTemplate, LibBuiltin<"math.h"> {
let AddBuiltinPrefixedAlias = 1;
}

def Abs : IntMathTemplate, LibBuiltin<"math.h"> {
let Spellings = ["abs"];
let Attributes = [NoThrow, Const];
let Prototype = "T(T)";
let AddBuiltinPrefixedAlias = 1;
}

def Copysign : FPMathTemplate, LibBuiltin<"math.h"> {
let Spellings = ["copysign"];
let Attributes = [NoThrow, Const];
Expand Down Expand Up @@ -3996,8 +4012,16 @@ def BlockObjectDispose : LibBuiltin<"blocks.h"> {
}
// FIXME: Also declare NSConcreteGlobalBlock and NSConcreteStackBlock.

def __Addressof : LangBuiltin<"CXX_LANG"> {
let Spellings = ["__addressof"];
let Attributes = [FunctionWithoutBuiltinPrefix, NoThrow, Const,
IgnoreSignature, Constexpr];
let Prototype = "void*(void&)";
let Namespace = "std";
}

def Addressof : CxxLibBuiltin<"memory"> {
let Spellings = ["addressof", "__addressof"];
let Spellings = ["addressof"];
let Attributes = [NoThrow, Const, IgnoreSignature, RequireDeclaration,
Constexpr];
let Prototype = "void*(void&)";
Expand Down Expand Up @@ -4036,7 +4060,7 @@ def Move : CxxLibBuiltin<"utility"> {
let Namespace = "std";
}

def MoveIfNsoexcept : CxxLibBuiltin<"memory"> {
def MoveIfNsoexcept : CxxLibBuiltin<"utility"> {
let Spellings = ["move_if_noexcept"];
let Attributes = [NoThrow, Const, IgnoreSignature, RequireDeclaration,
Constexpr];
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/BuiltinsBase.td
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ def UnevaluatedArguments : Attribute<"u">;
// is required for a builtin.
def FunctionWithBuiltinPrefix : Attribute<"F">;

def FunctionWithoutBuiltinPrefix : Attribute<"f">;

// const, but only when -fno-math-errno and FP exceptions are ignored.
def ConstIgnoringErrnoAndExceptions : Attribute<"e">;

Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -9901,7 +9901,7 @@ def err_lifetimebound_ctor_dtor : Error<
// CHECK: returning address/reference of stack memory
def warn_ret_stack_addr_ref : Warning<
"%select{address of|reference to}0 stack memory associated with "
"%select{local variable|parameter}2 %1 returned">,
"%select{local variable|parameter|compound literal}2 %1 returned">,
InGroup<ReturnStackAddress>;
def warn_ret_local_temp_addr_ref : Warning<
"returning %select{address of|reference to}0 local temporary object">,
Expand Down
10 changes: 0 additions & 10 deletions clang/include/clang/Driver/Driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -615,16 +615,6 @@ class Driver {
// FIXME: This should be in CompilationInfo.
std::string GetProgramPath(StringRef Name, const ToolChain &TC) const;

/// Lookup the path to the Standard library module manifest.
///
/// \param C - The compilation.
/// \param TC - The tool chain for additional information on
/// directories to search.
//
// FIXME: This should be in CompilationInfo.
std::string GetStdModuleManifestPath(const Compilation &C,
const ToolChain &TC) const;

/// HandleAutocompletions - Handle --autocomplete by searching and printing
/// possible flags, descriptions, and its arguments.
void HandleAutocompletions(StringRef PassedFlags) const;
Expand Down
3 changes: 0 additions & 3 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -5364,9 +5364,6 @@ def print_resource_dir : Flag<["-", "--"], "print-resource-dir">,
def print_search_dirs : Flag<["-", "--"], "print-search-dirs">,
HelpText<"Print the paths used for finding libraries and programs">,
Visibility<[ClangOption, CLOption]>;
def print_std_module_manifest_path : Flag<["-", "--"], "print-library-module-manifest-path">,
HelpText<"Print the path for the C++ Standard library module manifest">,
Visibility<[ClangOption, CLOption]>;
def print_targets : Flag<["-", "--"], "print-targets">,
HelpText<"Print the registered targets">,
Visibility<[ClangOption, CLOption]>;
Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/Format/Format.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,9 @@ struct FormatStyle {
/// For example, to align across empty lines and not across comments, either
/// of these work.
/// \code
/// AlignConsecutiveMacros: AcrossEmptyLines
/// <option-name>: AcrossEmptyLines
///
/// AlignConsecutiveMacros:
/// <option-name>:
/// Enabled: true
/// AcrossEmptyLines: true
/// AcrossComments: false
Expand Down
35 changes: 35 additions & 0 deletions clang/include/clang/InstallAPI/Frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ namespace installapi {
using SymbolFlags = llvm::MachO::SymbolFlags;
using RecordLinkage = llvm::MachO::RecordLinkage;
using GlobalRecord = llvm::MachO::GlobalRecord;
using ObjCContainerRecord = llvm::MachO::ObjCContainerRecord;
using ObjCInterfaceRecord = llvm::MachO::ObjCInterfaceRecord;
using ObjCCategoryRecord = llvm::MachO::ObjCCategoryRecord;
using ObjCIVarRecord = llvm::MachO::ObjCIVarRecord;

// Represents a collection of frontend records for a library that are tied to a
// darwin target triple.
Expand Down Expand Up @@ -69,6 +72,38 @@ class FrontendRecordsSlice : public llvm::MachO::RecordsSlice {
const Decl *D, HeaderType Access,
bool IsEHType);

/// Add ObjC Category record with attributes from AST.
///
/// \param ClassToExtend The name of class that is extended by category, not
/// symbol.
/// \param CategoryName The name of category, not symbol.
/// \param Avail The availability information tied
/// to the active target triple.
/// \param D The pointer to the declaration from traversing AST.
/// \param Access The intended access level of symbol.
/// \return The non-owning pointer to added record in slice.
ObjCCategoryRecord *addObjCCategory(StringRef ClassToExtend,
StringRef CategoryName,
const clang::AvailabilityInfo Avail,
const Decl *D, HeaderType Access);

/// Add ObjC IVar record with attributes from AST.
///
/// \param Container The owning pointer for instance variable.
/// \param Name The name of ivar, not symbol.
/// \param Linkage The linkage of symbol.
/// \param Avail The availability information tied to the active target
/// triple.
/// \param D The pointer to the declaration from traversing AST.
/// \param Access The intended access level of symbol.
/// \param AC The access control tied to the ivar declaration.
/// \return The non-owning pointer to added record in slice.
ObjCIVarRecord *addObjCIVar(ObjCContainerRecord *Container,
StringRef IvarName, RecordLinkage Linkage,
const clang::AvailabilityInfo Avail,
const Decl *D, HeaderType Access,
const clang::ObjCIvarDecl::AccessControl AC);

private:
/// Frontend information captured about records.
struct FrontendAttrs {
Expand Down
12 changes: 12 additions & 0 deletions clang/include/clang/InstallAPI/Visitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,22 @@ class InstallAPIVisitor final : public ASTConsumer,
/// ivars, properties, and methods of the class.
bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D);

/// Collect Objective-C Category/Extension declarations.
///
/// The class that is being extended might come from a different library and
/// is therefore itself not collected.
bool VisitObjCCategoryDecl(const ObjCCategoryDecl *D);

private:
std::string getMangledName(const NamedDecl *D) const;
std::string getBackendMangledName(llvm::Twine Name) const;
std::optional<HeaderType> getAccessForDecl(const NamedDecl *D) const;
void recordObjCInstanceVariables(
const ASTContext &ASTCtx, llvm::MachO::ObjCContainerRecord *Record,
StringRef SuperClass,
const llvm::iterator_range<
DeclContext::specific_decl_iterator<ObjCIvarDecl>>
Ivars);

InstallAPIContext &Ctx;
SourceManager &SrcMgr;
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
4 changes: 4 additions & 0 deletions clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
Original file line number Diff line number Diff line change
Expand Up @@ -1654,6 +1654,10 @@ def StdCLibraryFunctionsTesterChecker : Checker<"StdCLibraryFunctionsTester">,
WeakDependencies<[StdCLibraryFunctionsChecker]>,
Documentation<NotDocumented>;

def CheckerDocumentationChecker : Checker<"CheckerDocumentation">,
HelpText<"Defines an empty checker callback for all possible handlers.">,
Documentation<NotDocumented>;

} // end "debug"


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,12 +149,6 @@ class CoreEngine {
bool ExecuteWorkList(const LocationContext *L, unsigned Steps,
ProgramStateRef InitState);

/// Returns true if there is still simulation state on the worklist.
bool ExecuteWorkListWithInitialState(const LocationContext *L,
unsigned Steps,
ProgramStateRef InitState,
ExplodedNodeSet &Dst);

/// Dispatch the work list item based on the given location information.
/// Use Pred parameter as the predecessor state.
void dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc,
Expand Down
10 changes: 0 additions & 10 deletions clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,16 +190,6 @@ class ExprEngine {
return Engine.ExecuteWorkList(L, Steps, nullptr);
}

/// Execute the work list with an initial state. Nodes that reaches the exit
/// of the function are added into the Dst set, which represent the exit
/// state of the function call. Returns true if there is still simulation
/// state on the worklist.
bool ExecuteWorkListWithInitialState(const LocationContext *L, unsigned Steps,
ProgramStateRef InitState,
ExplodedNodeSet &Dst) {
return Engine.ExecuteWorkListWithInitialState(L, Steps, InitState, Dst);
}

/// getContext - Return the ASTContext associated with this analysis.
ASTContext &getContext() const { return AMgr.getASTContext(); }

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: 6 additions & 2 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2778,7 +2778,9 @@ static bool CheckedIntArithmetic(EvalInfo &Info, const Expr *E,
if (Info.checkingForUndefinedBehavior())
Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
diag::warn_integer_constant_overflow)
<< toString(Result, 10) << E->getType() << E->getSourceRange();
<< toString(Result, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
/*UpperCase=*/true, /*InsertSeparators=*/true)
<< E->getType() << E->getSourceRange();
return HandleOverflow(Info, E, Value, E->getType());
}
return true;
Expand Down Expand Up @@ -13910,7 +13912,9 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
if (Info.checkingForUndefinedBehavior())
Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
diag::warn_integer_constant_overflow)
<< toString(Value, 10) << E->getType() << E->getSourceRange();
<< toString(Value, 10, Value.isSigned(), /*formatAsCLiteral=*/false,
/*UpperCase=*/true, /*InsertSeparators=*/true)
<< E->getType() << E->getSourceRange();

if (!HandleOverflow(Info, E, -Value.extend(Value.getBitWidth() + 1),
E->getType()))
Expand Down
1 change: 0 additions & 1 deletion 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
18 changes: 14 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 @@ -2730,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 @@ -2741,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
23 changes: 20 additions & 3 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,9 @@ bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
QualType Type = E->getType();
if (S.checkingForUndefinedBehavior()) {
SmallString<32> Trunc;
Value.trunc(Result.bitWidth()).toString(Trunc, 10);
Value.trunc(Result.bitWidth())
.toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
/*UpperCase=*/true, /*InsertSeparators=*/true);
auto Loc = E->getExprLoc();
S.report(Loc, diag::warn_integer_constant_overflow)
<< Trunc << Type << E->getSourceRange();
Expand Down Expand Up @@ -499,7 +501,9 @@ bool Neg(InterpState &S, CodePtr OpPC) {

if (S.checkingForUndefinedBehavior()) {
SmallString<32> Trunc;
NegatedValue.trunc(Result.bitWidth()).toString(Trunc, 10);
NegatedValue.trunc(Result.bitWidth())
.toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
/*UpperCase=*/true, /*InsertSeparators=*/true);
auto Loc = E->getExprLoc();
S.report(Loc, diag::warn_integer_constant_overflow)
<< Trunc << Type << E->getSourceRange();
Expand Down Expand Up @@ -561,7 +565,9 @@ bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
QualType Type = E->getType();
if (S.checkingForUndefinedBehavior()) {
SmallString<32> Trunc;
APResult.trunc(Result.bitWidth()).toString(Trunc, 10);
APResult.trunc(Result.bitWidth())
.toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
/*UpperCase=*/true, /*InsertSeparators=*/true);
auto Loc = E->getExprLoc();
S.report(Loc, diag::warn_integer_constant_overflow)
<< Trunc << Type << E->getSourceRange();
Expand Down Expand Up @@ -746,6 +752,17 @@ inline bool CmpHelperEQ<FunctionPointer>(InterpState &S, CodePtr OpPC,
CompareFn Fn) {
const auto &RHS = S.Stk.pop<FunctionPointer>();
const auto &LHS = S.Stk.pop<FunctionPointer>();

// We cannot compare against weak declarations at compile time.
for (const auto &FP : {LHS, RHS}) {
if (!FP.isZero() && FP.getFunction()->getDecl()->isWeak()) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
<< FP.toDiagnosticString(S.getCtx());
return false;
}
}

S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS))));
return true;
}
Expand Down
27 changes: 24 additions & 3 deletions clang/lib/AST/Interp/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
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,6 +1222,11 @@ 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)
Expand Down
16 changes: 14 additions & 2 deletions clang/lib/CodeGen/CGHLSLRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "clang/AST/Decl.h"
#include "clang/Basic/TargetOptions.h"
#include "llvm/IR/IntrinsicsDirectX.h"
#include "llvm/IR/IntrinsicsSPIRV.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/FormatVariadic.h"
Expand Down Expand Up @@ -342,8 +343,19 @@ llvm::Value *CGHLSLRuntime::emitInputSemantic(IRBuilder<> &B,
return B.CreateCall(FunctionCallee(DxGroupIndex));
}
if (D.hasAttr<HLSLSV_DispatchThreadIDAttr>()) {
llvm::Function *DxThreadID = CGM.getIntrinsic(Intrinsic::dx_thread_id);
return buildVectorInput(B, DxThreadID, Ty);
llvm::Function *ThreadIDIntrinsic;
switch (CGM.getTarget().getTriple().getArch()) {
case llvm::Triple::dxil:
ThreadIDIntrinsic = CGM.getIntrinsic(Intrinsic::dx_thread_id);
break;
case llvm::Triple::spirv:
ThreadIDIntrinsic = CGM.getIntrinsic(Intrinsic::spv_thread_id);
break;
default:
llvm_unreachable("Input semantic not supported by target");
break;
}
return buildVectorInput(B, ThreadIDIntrinsic, Ty);
}
assert(false && "Unhandled parameter attribute");
return nullptr;
Expand Down
20 changes: 14 additions & 6 deletions clang/lib/CodeGen/CGObjCMac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1593,12 +1593,20 @@ class CGObjCNonFragileABIMac : public CGObjCCommonMac {
}

bool isClassLayoutKnownStatically(const ObjCInterfaceDecl *ID) {
// NSObject is a fixed size. If we can see the @implementation of a class
// which inherits from NSObject then we know that all it's offsets also must
// be fixed. FIXME: Can we do this if see a chain of super classes with
// implementations leading to NSObject?
return ID->getImplementation() && ID->getSuperClass() &&
ID->getSuperClass()->getName() == "NSObject";
// Test a class by checking its superclasses up to
// its base class if it has one.
for (; ID; ID = ID->getSuperClass()) {
// The layout of base class NSObject
// is guaranteed to be statically known
if (ID->getIdentifier()->getName() == "NSObject")
return true;

// If we cannot see the @implementation of a class,
// we cannot statically know the class layout.
if (!ID->getImplementation())
return false;
}
return false;
}

public:
Expand Down
44 changes: 0 additions & 44 deletions clang/lib/Driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2196,12 +2196,6 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
return false;
}

if (C.getArgs().hasArg(options::OPT_print_std_module_manifest_path)) {
llvm::outs() << GetStdModuleManifestPath(C, C.getDefaultToolChain())
<< '\n';
return false;
}

if (C.getArgs().hasArg(options::OPT_print_runtime_dir)) {
if (std::optional<std::string> RuntimePath = TC.getRuntimePath())
llvm::outs() << *RuntimePath << '\n';
Expand Down Expand Up @@ -6174,44 +6168,6 @@ std::string Driver::GetProgramPath(StringRef Name, const ToolChain &TC) const {
return std::string(Name);
}

std::string Driver::GetStdModuleManifestPath(const Compilation &C,
const ToolChain &TC) const {
std::string error = "<NOT PRESENT>";

switch (TC.GetCXXStdlibType(C.getArgs())) {
case ToolChain::CST_Libcxx: {
std::string lib = GetFilePath("libc++.so", TC);

// Note when there are multiple flavours of libc++ the module json needs to
// look at the command-line arguments for the proper json.
// These flavours do not exist at the moment, but there are plans to
// provide a variant that is built with sanitizer instrumentation enabled.

// For example
// StringRef modules = [&] {
// const SanitizerArgs &Sanitize = TC.getSanitizerArgs(C.getArgs());
// if (Sanitize.needsAsanRt())
// return "modules-asan.json";
// return "modules.json";
// }();

SmallString<128> path(lib.begin(), lib.end());
llvm::sys::path::remove_filename(path);
llvm::sys::path::append(path, "modules.json");
if (TC.getVFS().exists(path))
return static_cast<std::string>(path);

return error;
}

case ToolChain::CST_Libstdcxx:
// libstdc++ does not provide Standard library modules yet.
return error;
}

return error;
}

std::string Driver::GetTemporaryPath(StringRef Prefix, StringRef Suffix) const {
SmallString<128> Path;
std::error_code EC = llvm::sys::fs::createTemporaryFile(Prefix, Suffix, Path);
Expand Down
11 changes: 8 additions & 3 deletions clang/lib/Driver/ToolChains/FreeBSD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const char *LinkingOutput) const {
const auto &ToolChain = static_cast<const FreeBSD &>(getToolChain());
const Driver &D = ToolChain.getDriver();
const llvm::Triple &Triple = ToolChain.getTriple();
const llvm::Triple::ArchType Arch = ToolChain.getArch();
const bool IsPIE =
!Args.hasArg(options::OPT_shared) &&
Expand Down Expand Up @@ -165,8 +166,7 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-dynamic-linker");
CmdArgs.push_back("/libexec/ld-elf.so.1");
}
const llvm::Triple &T = ToolChain.getTriple();
if (Arch == llvm::Triple::arm || T.isX86())
if (Arch == llvm::Triple::arm || Triple.isX86())
CmdArgs.push_back("--hash-style=both");
CmdArgs.push_back("--enable-new-dtags");
}
Expand Down Expand Up @@ -212,12 +212,17 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
case llvm::Triple::riscv64:
CmdArgs.push_back("-m");
CmdArgs.push_back("elf64lriscv");
CmdArgs.push_back("-X");
break;
default:
break;
}

if (Triple.isRISCV64()) {
CmdArgs.push_back("-X");
if (Args.hasArg(options::OPT_mno_relax))
CmdArgs.push_back("--no-relax");
}

if (Arg *A = Args.getLastArg(options::OPT_G)) {
if (ToolChain.getTriple().isMIPS()) {
StringRef v = A->getValue();
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Driver/ToolChains/Fuchsia.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,11 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(Dyld));
}

if (ToolChain.getArch() == llvm::Triple::riscv64)
if (Triple.isRISCV64()) {
CmdArgs.push_back("-X");
if (Args.hasArg(options::OPT_mno_relax))
CmdArgs.push_back("--no-relax");
}

CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
Expand Down
7 changes: 5 additions & 2 deletions clang/lib/Driver/ToolChains/Haiku.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ void haiku::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const char *LinkingOutput) const {
const auto &ToolChain = static_cast<const Haiku &>(getToolChain());
const Driver &D = ToolChain.getDriver();
const llvm::Triple::ArchType Arch = ToolChain.getArch();
const llvm::Triple &Triple = ToolChain.getTriple();
const bool Static = Args.hasArg(options::OPT_static);
const bool Shared = Args.hasArg(options::OPT_shared);
ArgStringList CmdArgs;
Expand Down Expand Up @@ -61,8 +61,11 @@ void haiku::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (!Shared)
CmdArgs.push_back("--no-undefined");

if (Arch == llvm::Triple::riscv64)
if (Triple.isRISCV64()) {
CmdArgs.push_back("-X");
if (Args.hasArg(options::OPT_mno_relax))
CmdArgs.push_back("--no-relax");
}

assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
if (Output.isFilename()) {
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Driver/ToolChains/NetBSD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,8 +240,11 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
break;
}

if (Triple.isRISCV())
if (Triple.isRISCV()) {
CmdArgs.push_back("-X");
if (Args.hasArg(options::OPT_mno_relax))
CmdArgs.push_back("--no-relax");
}

assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
if (Output.isFilename()) {
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/Driver/ToolChains/OpenBSD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const char *LinkingOutput) const {
const auto &ToolChain = static_cast<const OpenBSD &>(getToolChain());
const Driver &D = ToolChain.getDriver();
const llvm::Triple &Triple = ToolChain.getTriple();
const llvm::Triple::ArchType Arch = ToolChain.getArch();
const bool Static = Args.hasArg(options::OPT_static);
const bool Shared = Args.hasArg(options::OPT_shared);
Expand Down Expand Up @@ -160,8 +161,11 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (Nopie || Profiling)
CmdArgs.push_back("-nopie");

if (Arch == llvm::Triple::riscv64)
if (Triple.isRISCV64()) {
CmdArgs.push_back("-X");
if (Args.hasArg(options::OPT_mno_relax))
CmdArgs.push_back("--no-relax");
}

assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
if (Output.isFilename()) {
Expand Down
25 changes: 25 additions & 0 deletions clang/lib/InstallAPI/Frontend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,31 @@ ObjCInterfaceRecord *FrontendRecordsSlice::addObjCInterface(
return ObjCR;
}

ObjCCategoryRecord *FrontendRecordsSlice::addObjCCategory(
StringRef ClassToExtend, StringRef CategoryName,
const clang::AvailabilityInfo Avail, const Decl *D, HeaderType Access) {
auto *ObjCR =
llvm::MachO::RecordsSlice::addObjCCategory(ClassToExtend, CategoryName);
FrontendRecords.insert({ObjCR, FrontendAttrs{Avail, D, Access}});
return ObjCR;
}

ObjCIVarRecord *FrontendRecordsSlice::addObjCIVar(
ObjCContainerRecord *Container, StringRef IvarName, RecordLinkage Linkage,
const clang::AvailabilityInfo Avail, const Decl *D, HeaderType Access,
const clang::ObjCIvarDecl::AccessControl AC) {
// If the decl otherwise would have been exported, check their access control.
// Ivar's linkage is also determined by this.
if ((Linkage == RecordLinkage::Exported) &&
((AC == ObjCIvarDecl::Private) || (AC == ObjCIvarDecl::Package)))
Linkage = RecordLinkage::Internal;
auto *ObjCR =
llvm::MachO::RecordsSlice::addObjCIVar(Container, IvarName, Linkage);
FrontendRecords.insert({ObjCR, FrontendAttrs{Avail, D, Access}});

return nullptr;
}

std::optional<HeaderType>
InstallAPIContext::findAndRecordFile(const FileEntry *FE,
const Preprocessor &PP) {
Expand Down
51 changes: 50 additions & 1 deletion clang/lib/InstallAPI/Visitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,29 @@ static bool hasObjCExceptionAttribute(const ObjCInterfaceDecl *D) {

return false;
}
void InstallAPIVisitor::recordObjCInstanceVariables(
const ASTContext &ASTCtx, ObjCContainerRecord *Record, StringRef SuperClass,
const llvm::iterator_range<
DeclContext::specific_decl_iterator<ObjCIvarDecl>>
Ivars) {
RecordLinkage Linkage = RecordLinkage::Exported;
const RecordLinkage ContainerLinkage = Record->getLinkage();
// If fragile, set to unknown.
if (ASTCtx.getLangOpts().ObjCRuntime.isFragile())
Linkage = RecordLinkage::Unknown;
// Linkage should be inherited from container.
else if (ContainerLinkage != RecordLinkage::Unknown)
Linkage = ContainerLinkage;
for (const auto *IV : Ivars) {
auto Access = getAccessForDecl(IV);
if (!Access)
continue;
StringRef Name = IV->getName();
const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(IV);
auto AC = IV->getCanonicalAccessControl();
Ctx.Slice->addObjCIVar(Record, Name, Linkage, Avail, IV, *Access, AC);
}
}

bool InstallAPIVisitor::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
// Skip forward declaration for classes (@class)
Expand All @@ -118,7 +141,33 @@ bool InstallAPIVisitor::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
(!D->getASTContext().getLangOpts().ObjCRuntime.isFragile() &&
hasObjCExceptionAttribute(D));

Ctx.Slice->addObjCInterface(Name, Linkage, Avail, D, *Access, IsEHType);
ObjCInterfaceRecord *Class =
Ctx.Slice->addObjCInterface(Name, Linkage, Avail, D, *Access, IsEHType);

// Get base class.
StringRef SuperClassName;
if (const auto *SuperClass = D->getSuperClass())
SuperClassName = SuperClass->getObjCRuntimeNameAsString();

recordObjCInstanceVariables(D->getASTContext(), Class, SuperClassName,
D->ivars());
return true;
}

bool InstallAPIVisitor::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
StringRef CategoryName = D->getName();
// Skip over declarations that access could not be collected for.
auto Access = getAccessForDecl(D);
if (!Access)
return true;
const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D);
const ObjCInterfaceDecl *InterfaceD = D->getClassInterface();
const StringRef InterfaceName = InterfaceD->getName();

ObjCCategoryRecord *Category = Ctx.Slice->addObjCCategory(
InterfaceName, CategoryName, Avail, D, *Access);
recordObjCInstanceVariables(D->getASTContext(), Category, InterfaceName,
D->ivars());
return true;
}

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
8 changes: 6 additions & 2 deletions clang/lib/Parse/ParseExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3908,7 +3908,10 @@ ExprResult Parser::ParseTypeTrait() {
SmallVector<ParsedType, 2> Args;
do {
// Parse the next type.
TypeResult Ty = ParseTypeName();
TypeResult Ty =
ParseTypeName(/*SourceRange=*/nullptr,
getLangOpts().CPlusPlus ? DeclaratorContext::TemplateArg
: DeclaratorContext::TypeName);
if (Ty.isInvalid()) {
Parens.skipToEnd();
return ExprError();
Expand Down Expand Up @@ -3950,7 +3953,8 @@ ExprResult Parser::ParseArrayTypeTrait() {
if (T.expectAndConsume())
return ExprError();

TypeResult Ty = ParseTypeName();
TypeResult Ty =
ParseTypeName(/*SourceRange=*/nullptr, DeclaratorContext::TemplateArg);
if (Ty.isInvalid()) {
SkipUntil(tok::comma, StopAtSemi);
SkipUntil(tok::r_paren, StopAtSemi);
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Parse/ParseOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,8 @@ bool doesDirectiveHaveAssociatedStmt(OpenACCDirectiveKind DirKind) {
default:
return false;
case OpenACCDirectiveKind::Parallel:
case OpenACCDirectiveKind::Serial:
case OpenACCDirectiveKind::Kernels:
return true;
}
llvm_unreachable("Unhandled directive->assoc stmt");
Expand All @@ -563,6 +565,8 @@ bool doesDirectiveHaveAssociatedStmt(OpenACCDirectiveKind DirKind) {
unsigned getOpenACCScopeFlags(OpenACCDirectiveKind DirKind) {
switch (DirKind) {
case OpenACCDirectiveKind::Parallel:
case OpenACCDirectiveKind::Serial:
case OpenACCDirectiveKind::Kernels:
// Mark this as a BreakScope/ContinueScope as well as a compute construct
// so that we can diagnose trying to 'break'/'continue' inside of one.
return Scope::BreakScope | Scope::ContinueScope |
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
30 changes: 14 additions & 16 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17624,31 +17624,29 @@ class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> {
return VisitExpr(CCE);

// In C++11, list initializations are sequenced.
SmallVector<SequenceTree::Seq, 32> Elts;
SequenceTree::Seq Parent = Region;
for (CXXConstructExpr::const_arg_iterator I = CCE->arg_begin(),
E = CCE->arg_end();
I != E; ++I) {
Region = Tree.allocate(Parent);
Elts.push_back(Region);
Visit(*I);
}

// Forget that the initializers are sequenced.
Region = Parent;
for (unsigned I = 0; I < Elts.size(); ++I)
Tree.merge(Elts[I]);
SequenceExpressionsInOrder(
llvm::ArrayRef(CCE->getArgs(), CCE->getNumArgs()));
}

void VisitInitListExpr(const InitListExpr *ILE) {
if (!SemaRef.getLangOpts().CPlusPlus11)
return VisitExpr(ILE);

// In C++11, list initializations are sequenced.
SequenceExpressionsInOrder(ILE->inits());
}

void VisitCXXParenListInitExpr(const CXXParenListInitExpr *PLIE) {
// C++20 parenthesized list initializations are sequenced. See C++20
// [decl.init.general]p16.5 and [decl.init.general]p16.6.2.2.
SequenceExpressionsInOrder(PLIE->getInitExprs());
}

private:
void SequenceExpressionsInOrder(ArrayRef<const Expr *> ExpressionList) {
SmallVector<SequenceTree::Seq, 32> Elts;
SequenceTree::Seq Parent = Region;
for (unsigned I = 0; I < ILE->getNumInits(); ++I) {
const Expr *E = ILE->getInit(I);
for (const Expr *E : ExpressionList) {
if (!E)
continue;
Region = Tree.allocate(Parent);
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1110,7 +1110,9 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
// unqualified-id followed by a < and name lookup finds either one
// or more functions or finds nothing.
if (!IsFilteredTemplateName)
FilterAcceptableTemplateNames(Result);
FilterAcceptableTemplateNames(Result,
/*AllowFunctionTemplates=*/true,
/*AllowDependent=*/true);

bool IsFunctionTemplate;
bool IsVarTemplate;
Expand All @@ -1120,6 +1122,7 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
Template = Context.getOverloadedTemplateName(Result.begin(),
Result.end());
} else if (!Result.empty()) {
assert(!Result.isUnresolvableResult());
auto *TD = cast<TemplateDecl>(getAsTemplateNameDecl(
*Result.begin(), /*AllowFunctionTemplates=*/true,
/*AllowDependent=*/false));
Expand Down
6 changes: 0 additions & 6 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6227,12 +6227,6 @@ struct ImmediateCallVisitor : public RecursiveASTVisitor<ImmediateCallVisitor> {
return VisitCXXMethodDecl(E->getCallOperator());
}

// Blocks don't support default parameters, and, as for lambdas,
// we don't consider their body a subexpression.
bool VisitBlockDecl(BlockDecl *B) { return false; }

bool VisitCompoundStmt(CompoundStmt *B) { return false; }

bool VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
return TraverseStmt(E->getExpr());
}
Expand Down
12 changes: 12 additions & 0 deletions clang/lib/Sema/SemaInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7734,6 +7734,14 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
break;
}

case Stmt::CompoundLiteralExprClass: {
if (auto *CLE = dyn_cast<CompoundLiteralExpr>(Init)) {
if (!CLE->isFileScope())
Visit(Path, Local(CLE), RK);
}
break;
}

// FIXME: Visit the left-hand side of an -> or ->*.

default:
Expand Down Expand Up @@ -8289,6 +8297,10 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
if (LK == LK_StmtExprResult)
return false;
Diag(DiagLoc, diag::warn_ret_addr_label) << DiagRange;
} else if (auto *CLE = dyn_cast<CompoundLiteralExpr>(L)) {
Diag(DiagLoc, diag::warn_ret_stack_addr_ref)
<< Entity.getType()->isReferenceType() << CLE->getInitializer() << 2
<< DiagRange;
} else {
Diag(DiagLoc, diag::warn_ret_local_temp_addr_ref)
<< Entity.getType()->isReferenceType() << DiagRange;
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/Sema/SemaOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ bool diagnoseConstructAppertainment(Sema &S, OpenACCDirectiveKind K,
// do anything.
break;
case OpenACCDirectiveKind::Parallel:
case OpenACCDirectiveKind::Serial:
case OpenACCDirectiveKind::Kernels:
if (!IsStmt)
return S.Diag(StartLoc, diag::err_acc_construct_appertainment) << K;
break;
Expand Down Expand Up @@ -55,6 +57,8 @@ void Sema::ActOnOpenACCConstruct(OpenACCDirectiveKind K,
// rules anywhere.
break;
case OpenACCDirectiveKind::Parallel:
case OpenACCDirectiveKind::Serial:
case OpenACCDirectiveKind::Kernels:
// Nothing to do here, there is no real legalization that needs to happen
// here as these constructs do not take any arguments.
break;
Expand All @@ -79,6 +83,8 @@ StmtResult Sema::ActOnEndOpenACCStmtDirective(OpenACCDirectiveKind K,
case OpenACCDirectiveKind::Invalid:
return StmtError();
case OpenACCDirectiveKind::Parallel:
case OpenACCDirectiveKind::Serial:
case OpenACCDirectiveKind::Kernels:
return OpenACCComputeConstruct::Create(
getASTContext(), K, StartLoc, EndLoc,
AssocStmt.isUsable() ? AssocStmt.get() : nullptr);
Expand All @@ -92,6 +98,8 @@ StmtResult Sema::ActOnOpenACCAssociatedStmt(OpenACCDirectiveKind K,
default:
llvm_unreachable("Unimplemented associated statement application");
case OpenACCDirectiveKind::Parallel:
case OpenACCDirectiveKind::Serial:
case OpenACCDirectiveKind::Kernels:
// There really isn't any checking here that could happen. As long as we
// have a statement to associate, this should be fine.
// OpenACC 3.3 Section 6:
Expand Down
10 changes: 6 additions & 4 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -491,18 +491,20 @@ bool Sema::LookupTemplateName(LookupResult &Found,
// To keep our behavior consistent, we apply the "finds nothing" part in
// all language modes, and diagnose the empty lookup in ActOnCallExpr if we
// successfully form a call to an undeclared template-id.
bool AllFunctions =
getLangOpts().CPlusPlus20 && llvm::all_of(Found, [](NamedDecl *ND) {
bool AnyFunctions =
getLangOpts().CPlusPlus20 && llvm::any_of(Found, [](NamedDecl *ND) {
return isa<FunctionDecl>(ND->getUnderlyingDecl());
});
if (AllFunctions || (Found.empty() && !IsDependent)) {
if (AnyFunctions || (Found.empty() && !IsDependent)) {
// If lookup found any functions, or if this is a name that can only be
// used for a function, then strongly assume this is a function
// template-id.
*ATK = (Found.empty() && Found.getLookupName().isIdentifier())
? AssumedTemplateKind::FoundNothing
: AssumedTemplateKind::FoundFunctions;
Found.clear();
FilterAcceptableTemplateNames(Found,
/*AllowFunctionTemplates*/ true,
/*AllowDependent*/ true);
return false;
}
}
Expand Down
13 changes: 9 additions & 4 deletions clang/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,7 @@ class CheckerDocumentation : public Checker< check::PreStmt<ReturnStmt>,
/// (2) and (3). Post-call for the allocator is called after step (1).
/// Pre-statement for the new-expression is called on step (4) when the value
/// of the expression is evaluated.
/// \param NE The C++ new-expression that triggered the allocation.
/// \param Target The allocated region, casted to the class type.
void checkNewAllocator(const CXXNewExpr *NE, SVal Target,
CheckerContext &) const {}
void checkNewAllocator(const CXXAllocatorCall &, CheckerContext &) const {}

/// Called on a load from and a store to a location.
///
Expand Down Expand Up @@ -330,5 +327,13 @@ void CheckerDocumentation::checkPostStmt(const DeclStmt *DS,
CheckerContext &C) const {
}

void registerCheckerDocumentationChecker(CheckerManager &Mgr) {
Mgr.registerChecker<CheckerDocumentation>();
}

bool shouldRegisterCheckerDocumentationChecker(const CheckerManager &) {
return false;
}

} // end namespace ento
} // end namespace clang
12 changes: 0 additions & 12 deletions clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,18 +222,6 @@ void CoreEngine::dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc,
}
}

bool CoreEngine::ExecuteWorkListWithInitialState(const LocationContext *L,
unsigned Steps,
ProgramStateRef InitState,
ExplodedNodeSet &Dst) {
bool DidNotFinish = ExecuteWorkList(L, Steps, InitState);
for (ExplodedGraph::eop_iterator I = G.eop_begin(), E = G.eop_end(); I != E;
++I) {
Dst.Add(*I);
}
return DidNotFinish;
}

void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) {
const CFGBlock *Blk = L.getDst();
NodeBuilderContext BuilderCtx(*this, Blk, Pred);
Expand Down
2 changes: 1 addition & 1 deletion clang/test/AST/Interp/c.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ int chooseexpr[__builtin_choose_expr(1, 1, expr)];

int somefunc(int i) {
return (i, 65537) * 65537; // all-warning {{left operand of comma operator has no effect}} \
// all-warning {{overflow in expression; result is 131073}}
// all-warning {{overflow in expression; result is 131'073 with type 'int'}}
}

/// FIXME: The following test is incorrect in the new interpreter.
Expand Down
20 changes: 15 additions & 5 deletions clang/test/AST/Interp/complex.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify -Wno-unused-value %s
// RUN: %clang_cc1 -verify=ref -Wno-unused-value %s

// expected-no-diagnostics
// ref-no-diagnostics
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=both,expected -Wno-unused-value %s
// RUN: %clang_cc1 -verify=both,ref -Wno-unused-value %s

constexpr _Complex double z1 = {1.0, 2.0};
static_assert(__real(z1) == 1.0, "");
Expand Down Expand Up @@ -256,3 +253,16 @@ namespace DeclRefCopy {
}
static_assert(localComplexArray() == (24 + 42), "");
}

namespace Builtin {
constexpr _Complex float A = __builtin_complex(10.0f, 20.0f);
static_assert(__real(A) == 10, "");
static_assert(__imag(A) == 20, "");

constexpr _Complex double B = __builtin_complex(10.0, 20.0);
static_assert(__real(B) == 10, "");
static_assert(__imag(B) == 20, "");


constexpr _Complex float C = __builtin_complex(10.0f, 20.0); // both-error {{arguments are of different types}}
}
10 changes: 10 additions & 0 deletions clang/test/AST/Interp/functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -565,3 +565,13 @@ namespace VariadicOperator {
float &fr = c(10);
}
}

namespace WeakCompare {
[[gnu::weak]]void weak_method();
static_assert(weak_method != nullptr, ""); // both-error {{not an integral constant expression}} \
// both-note {{comparison against address of weak declaration '&weak_method' can only be performed at runtim}}

constexpr auto A = &weak_method;
static_assert(A != nullptr, ""); // both-error {{not an integral constant expression}} \
// both-note {{comparison against address of weak declaration '&weak_method' can only be performed at runtim}}
}
Loading