4 changes: 2 additions & 2 deletions bolt/utils/docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM ubuntu:20.04 AS builder
FROM ubuntu:24.04 AS builder

ARG DEBIAN_FRONTEND=noninteractive
ENV TZ=UTC
Expand Down Expand Up @@ -26,6 +26,6 @@ RUN mkdir build && \
ninja install-llvm-bolt install-perf2bolt install-merge-fdata \
install-llvm-boltdiff install-bolt_rt

FROM ubuntu:20.04
FROM ubuntu:24.04

COPY --from=builder /home/bolt/install /usr/local
13 changes: 13 additions & 0 deletions clang-tools-extra/clang-doc/HTMLGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "llvm/Support/JSON.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <optional>
#include <string>

Expand Down Expand Up @@ -979,6 +980,18 @@ static llvm::Error serializeIndex(ClangDocContext &CDCtx) {
"error creating index file: " +
FileErr.message());
}
llvm::SmallString<128> RootPath(CDCtx.OutDirectory);
if (llvm::sys::path::is_relative(RootPath)) {
llvm::sys::fs::make_absolute(RootPath);
}
// Replace the escaped characters with a forward slash. It shouldn't matter
// when rendering the webpage in a web browser. This helps to prevent the
// JavaScript from escaping characters incorrectly, and introducing bad paths
// in the URLs.
std::string RootPathEscaped = RootPath.str().str();
std::replace(RootPathEscaped.begin(), RootPathEscaped.end(), '\\', '/');
OS << "var RootPath = \"" << RootPathEscaped << "\";\n";

CDCtx.Idx.sort();
llvm::json::OStream J(OS, 2);
std::function<void(Index)> IndexToJSON = [&](const Index &I) {
Expand Down
44 changes: 35 additions & 9 deletions clang-tools-extra/clang-doc/Mapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,28 @@
#include "clang/AST/Comment.h"
#include "clang/Index/USRGeneration.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Error.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Mutex.h"

namespace clang {
namespace doc {

static llvm::StringSet<> USRVisited;
static llvm::sys::Mutex USRVisitedGuard;

template <typename T> bool isTypedefAnonRecord(const T *D) {
if (const auto *C = dyn_cast<CXXRecordDecl>(D)) {
return C->getTypedefNameForAnonDecl();
}
return false;
}

void MapASTVisitor::HandleTranslationUnit(ASTContext &Context) {
TraverseDecl(Context.getTranslationUnitDecl());
}

template <typename T> bool MapASTVisitor::mapDecl(const T *D) {
template <typename T>
bool MapASTVisitor::mapDecl(const T *D, bool IsDefinition) {
// If we're looking a decl not in user files, skip this decl.
if (D->getASTContext().getSourceManager().isInSystemHeader(D->getLocation()))
return true;
Expand All @@ -34,6 +46,16 @@ template <typename T> bool MapASTVisitor::mapDecl(const T *D) {
// If there is an error generating a USR for the decl, skip this decl.
if (index::generateUSRForDecl(D, USR))
return true;
// Prevent Visiting USR twice
{
std::lock_guard<llvm::sys::Mutex> Guard(USRVisitedGuard);
StringRef Visited = USR.str();
if (USRVisited.count(Visited) && !isTypedefAnonRecord<T>(D))
return true;
// We considered a USR to be visited only when its defined
if (IsDefinition)
USRVisited.insert(Visited);
}
bool IsFileInRootDir;
llvm::SmallString<128> File =
getFile(D, D->getASTContext(), CDCtx.SourceRoot, IsFileInRootDir);
Expand All @@ -53,30 +75,34 @@ template <typename T> bool MapASTVisitor::mapDecl(const T *D) {
}

bool MapASTVisitor::VisitNamespaceDecl(const NamespaceDecl *D) {
return mapDecl(D);
return mapDecl(D, /*isDefinition=*/true);
}

bool MapASTVisitor::VisitRecordDecl(const RecordDecl *D) { return mapDecl(D); }
bool MapASTVisitor::VisitRecordDecl(const RecordDecl *D) {
return mapDecl(D, D->isThisDeclarationADefinition());
}

bool MapASTVisitor::VisitEnumDecl(const EnumDecl *D) { return mapDecl(D); }
bool MapASTVisitor::VisitEnumDecl(const EnumDecl *D) {
return mapDecl(D, D->isThisDeclarationADefinition());
}

bool MapASTVisitor::VisitCXXMethodDecl(const CXXMethodDecl *D) {
return mapDecl(D);
return mapDecl(D, D->isThisDeclarationADefinition());
}

bool MapASTVisitor::VisitFunctionDecl(const FunctionDecl *D) {
// Don't visit CXXMethodDecls twice
if (isa<CXXMethodDecl>(D))
return true;
return mapDecl(D);
return mapDecl(D, D->isThisDeclarationADefinition());
}

bool MapASTVisitor::VisitTypedefDecl(const TypedefDecl *D) {
return mapDecl(D);
return mapDecl(D, /*isDefinition=*/true);
}

bool MapASTVisitor::VisitTypeAliasDecl(const TypeAliasDecl *D) {
return mapDecl(D);
return mapDecl(D, /*isDefinition=*/true);
}

comments::FullComment *
Expand Down
2 changes: 1 addition & 1 deletion clang-tools-extra/clang-doc/Mapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class MapASTVisitor : public clang::RecursiveASTVisitor<MapASTVisitor>,
bool VisitTypeAliasDecl(const TypeAliasDecl *D);

private:
template <typename T> bool mapDecl(const T *D);
template <typename T> bool mapDecl(const T *D, bool IsDefinition);

int getLine(const NamedDecl *D, const ASTContext &Context) const;
llvm::SmallString<128> getFile(const NamedDecl *D, const ASTContext &Context,
Expand Down
51 changes: 13 additions & 38 deletions clang-tools-extra/clang-doc/assets/index.js
Original file line number Diff line number Diff line change
@@ -1,42 +1,17 @@
// Append using posix-style a file name or directory to Base
function append(Base, New) {
if (!New)
return Base;
if (Base)
Base += "/";
Base += New;
return Base;
}

// Get relative path to access FilePath from CurrentDirectory
function computeRelativePath(FilePath, CurrentDirectory) {
var Path = FilePath;
while (Path) {
if (CurrentDirectory == Path)
return FilePath.substring(Path.length + 1);
Path = Path.substring(0, Path.lastIndexOf("/"));
}

var Dir = CurrentDirectory;
var Result = "";
while (Dir) {
if (Dir == FilePath)
break;
Dir = Dir.substring(0, Dir.lastIndexOf("/"));
Result = append(Result, "..")
function genLink(Ref) {
// we treat the file paths different depending on if we're
// serving via a http server or viewing from a local
var Path = window.location.protocol.startsWith("file") ?
`${window.location.protocol}//${window.location.host}/${Ref.Path}` :
`${window.location.protocol}//${RootPath}/${Ref.Path}`;
if (Ref.RefType === "namespace") {
Path = `${Path}/index.html`
} else if (Ref.Path === "") {
Path = `${Path}${Ref.Name}.html`;
} else {
Path = `${Path}/${Ref.Name}.html`;
}
Result = append(Result, FilePath.substring(Dir.length))
return Result;
}

function genLink(Ref, CurrentDirectory) {
var Path = computeRelativePath(Ref.Path, CurrentDirectory);
if (Ref.RefType == "namespace")
Path = append(Path, "index.html");
else
Path = append(Path, Ref.Name + ".html")

ANode = document.createElement("a");
ANode = document.createElement("a");
ANode.setAttribute("href", Path);
var TextNode = document.createTextNode(Ref.Name);
ANode.appendChild(TextNode);
Expand Down
1 change: 0 additions & 1 deletion clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,6 @@ Example usage for a project using a compile commands database:
for (auto &Group : USRToBitcode) {
Pool.async([&]() {
std::vector<std::unique_ptr<doc::Info>> Infos;

for (auto &Bitcode : Group.getValue()) {
llvm::BitstreamCursor Stream(Bitcode);
doc::ClangDocBitcodeReader Reader(Stream);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,12 @@ void NonConstParameterCheck::diagnoseNonConstParameters() {
if (!Function)
continue;
unsigned Index = Par->getFunctionScopeIndex();
for (FunctionDecl *FnDecl : Function->redecls())
for (FunctionDecl *FnDecl : Function->redecls()) {
if (FnDecl->getNumParams() <= Index)
continue;
Fixes.push_back(FixItHint::CreateInsertion(
FnDecl->getParamDecl(Index)->getBeginLoc(), "const "));
}

diag(Par->getLocation(), "pointer parameter '%0' can be pointer to const")
<< Par->getName() << Fixes;
Expand Down
64 changes: 32 additions & 32 deletions clang-tools-extra/clang-tidy/utils/UseRangesCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,6 @@ static constexpr const char ArgName[] = "ArgName";

namespace clang::tidy::utils {

static bool operator==(const UseRangesCheck::Indexes &L,
const UseRangesCheck::Indexes &R) {
return std::tie(L.BeginArg, L.EndArg, L.ReplaceArg) ==
std::tie(R.BeginArg, R.EndArg, R.ReplaceArg);
}

static std::string getFullPrefix(ArrayRef<UseRangesCheck::Indexes> Signature) {
std::string Output;
llvm::raw_string_ostream OS(Output);
Expand All @@ -54,15 +48,6 @@ static std::string getFullPrefix(ArrayRef<UseRangesCheck::Indexes> Signature) {
return Output;
}

static llvm::hash_code hash_value(const UseRangesCheck::Indexes &Indexes) {
return llvm::hash_combine(Indexes.BeginArg, Indexes.EndArg,
Indexes.ReplaceArg);
}

static llvm::hash_code hash_value(const UseRangesCheck::Signature &Sig) {
return llvm::hash_combine_range(Sig.begin(), Sig.end());
}

namespace {

AST_MATCHER(Expr, hasSideEffects) {
Expand Down Expand Up @@ -123,32 +108,34 @@ makeMatcherPair(StringRef State, const UseRangesCheck::Indexes &Indexes,
}

void UseRangesCheck::registerMatchers(MatchFinder *Finder) {
Replaces = getReplacerMap();
auto Replaces = getReplacerMap();
ReverseDescriptor = getReverseDescriptor();
auto BeginEndNames = getFreeBeginEndMethods();
llvm::SmallVector<StringRef, 4> BeginNames{
llvm::make_first_range(BeginEndNames)};
llvm::SmallVector<StringRef, 4> EndNames{
llvm::make_second_range(BeginEndNames)};
llvm::DenseSet<ArrayRef<Signature>> Seen;
Replacers.clear();
llvm::DenseSet<Replacer *> SeenRepl;
for (auto I = Replaces.begin(), E = Replaces.end(); I != E; ++I) {
const ArrayRef<Signature> &Signatures =
I->getValue()->getReplacementSignatures();
if (!Seen.insert(Signatures).second)
auto Replacer = I->getValue();
if (!SeenRepl.insert(Replacer.get()).second)
continue;
assert(!Signatures.empty() &&
llvm::all_of(Signatures, [](auto Index) { return !Index.empty(); }));
Replacers.push_back(Replacer);
assert(!Replacer->getReplacementSignatures().empty() &&
llvm::all_of(Replacer->getReplacementSignatures(),
[](auto Index) { return !Index.empty(); }));
std::vector<StringRef> Names(1, I->getKey());
for (auto J = std::next(I); J != E; ++J)
if (J->getValue()->getReplacementSignatures() == Signatures)
if (J->getValue() == Replacer)
Names.push_back(J->getKey());

std::vector<ast_matchers::internal::DynTypedMatcher> TotalMatchers;
// As we match on the first matched signature, we need to sort the
// signatures in order of length(longest to shortest). This way any
// signature that is a subset of another signature will be matched after the
// other.
SmallVector<Signature> SigVec(Signatures);
SmallVector<Signature> SigVec(Replacer->getReplacementSignatures());
llvm::sort(SigVec, [](auto &L, auto &R) { return R.size() < L.size(); });
for (const auto &Signature : SigVec) {
std::vector<ast_matchers::internal::DynTypedMatcher> Matchers;
Expand All @@ -163,7 +150,8 @@ void UseRangesCheck::registerMatchers(MatchFinder *Finder) {
}
Finder->addMatcher(
callExpr(
callee(functionDecl(hasAnyName(std::move(Names))).bind(FuncDecl)),
callee(functionDecl(hasAnyName(std::move(Names)))
.bind((FuncDecl + Twine(Replacers.size() - 1).str()))),
ast_matchers::internal::DynTypedMatcher::constructVariadic(
ast_matchers::internal::DynTypedMatcher::VO_AnyOf,
ASTNodeKind::getFromNodeKind<CallExpr>(),
Expand Down Expand Up @@ -205,21 +193,33 @@ static void removeFunctionArgs(DiagnosticBuilder &Diag, const CallExpr &Call,
}

void UseRangesCheck::check(const MatchFinder::MatchResult &Result) {
const auto *Function = Result.Nodes.getNodeAs<FunctionDecl>(FuncDecl);
std::string Qualified = "::" + Function->getQualifiedNameAsString();
auto Iter = Replaces.find(Qualified);
assert(Iter != Replaces.end());
Replacer *Replacer = nullptr;
const FunctionDecl *Function = nullptr;
for (auto [Node, Value] : Result.Nodes.getMap()) {
StringRef NodeStr(Node);
if (!NodeStr.consume_front(FuncDecl))
continue;
Function = Value.get<FunctionDecl>();
size_t Index;
if (NodeStr.getAsInteger(10, Index)) {
llvm_unreachable("Unable to extract replacer index");
}
assert(Index < Replacers.size());
Replacer = Replacers[Index].get();
break;
}
assert(Replacer && Function);
SmallString<64> Buffer;
for (const Signature &Sig : Iter->getValue()->getReplacementSignatures()) {
for (const Signature &Sig : Replacer->getReplacementSignatures()) {
Buffer.assign({BoundCall, getFullPrefix(Sig)});
const auto *Call = Result.Nodes.getNodeAs<CallExpr>(Buffer);
if (!Call)
continue;
auto Diag = createDiag(*Call);
if (auto ReplaceName = Iter->getValue()->getReplaceName(*Function))
if (auto ReplaceName = Replacer->getReplaceName(*Function))
Diag << FixItHint::CreateReplacement(Call->getCallee()->getSourceRange(),
*ReplaceName);
if (auto Include = Iter->getValue()->getHeaderInclusion(*Function))
if (auto Include = Replacer->getHeaderInclusion(*Function))
Diag << Inserter.createIncludeInsertion(
Result.SourceManager->getFileID(Call->getBeginLoc()), *Include);
llvm::SmallVector<unsigned, 3> ToRemove;
Expand Down
2 changes: 1 addition & 1 deletion clang-tools-extra/clang-tidy/utils/UseRangesCheck.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class UseRangesCheck : public ClangTidyCheck {
std::optional<TraversalKind> getCheckTraversalKind() const override;

private:
ReplacerMap Replaces;
std::vector<llvm::IntrusiveRefCntPtr<Replacer>> Replacers;
std::optional<ReverseIteratorDescriptor> ReverseDescriptor;
IncludeInserter Inserter;
};
Expand Down
6 changes: 6 additions & 0 deletions clang-tools-extra/test/clang-doc/test-path-abs.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// RUN: rm -rf %t && mkdir %t
// RUN: clang-doc --format=html --executor=standalone %s --output=%t
// RUN: FileCheck %s -input-file=%t/index_json.js -check-prefix=JSON-INDEX
// RUN: rm -rf %t

// JSON-INDEX: var RootPath = "{{.*}}test-path-abs.cpp.tmp";
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ template <typename T> class vector {
public:
using iterator = T *;
using const_iterator = const T *;
using reverse_iterator = T*;
using reverse_const_iterator = const T*;
using reverse_iterator = T *;
using reverse_const_iterator = const T *;

constexpr const_iterator begin() const;
constexpr const_iterator end() const;
Expand Down Expand Up @@ -72,8 +72,8 @@ template <typename Container> constexpr auto crend(const Container &Cont) {
return Cont.crend();
}
// Find
template< class InputIt, class T >
InputIt find( InputIt first, InputIt last, const T& value );
template <class InputIt, class T>
InputIt find(InputIt first, InputIt last, const T &value);

// Reverse
template <typename Iter> void reverse(Iter begin, Iter end);
Expand All @@ -82,6 +82,7 @@ template <typename Iter> void reverse(Iter begin, Iter end);
template <class InputIt1, class InputIt2>
bool includes(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2);

inline namespace _V1 {
// IsPermutation
template <class ForwardIt1, class ForwardIt2>
bool is_permutation(ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2);
Expand All @@ -97,9 +98,10 @@ template <class InputIt1, class InputIt2>
bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2);

template <class InputIt1, class InputIt2, class BinaryPred>
bool equal(InputIt1 first1, InputIt1 last1,
InputIt2 first2, InputIt2 last2, BinaryPred p) {
// Need a definition to suppress undefined_internal_type when invoked with lambda
bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2,
BinaryPred p) {
// Need a definition to suppress undefined_internal_type when invoked with
// lambda
return true;
}

Expand All @@ -108,6 +110,7 @@ void iota(ForwardIt first, ForwardIt last, T value);

template <class ForwardIt>
ForwardIt rotate(ForwardIt first, ForwardIt middle, ForwardIt last);
} // namespace _V1

} // namespace std

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// RUN: %check_clang_tidy %s readability-non-const-parameter %t

static int f();

int f(p)
int *p;
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: pointer parameter 'p' can be pointer to const [readability-non-const-parameter]
// CHECK-FIXES: {{^}} const int *p;{{$}}
{
return *p;
}
17 changes: 17 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ Bug Fixes to C++ Support
^^^^^^^^^^^^^^^^^^^^^^^^

- Fixed a crash when an expression with a dependent ``__typeof__`` type is used as the operand of a unary operator. (#GH97646)
- Fixed a failed assertion when checking invalid delete operator declaration. (#GH96191)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -172,6 +173,22 @@ AMDGPU Support
X86 Support
^^^^^^^^^^^

- The MMX vector intrinsic functions from ``*mmintrin.h`` which
operate on `__m64` vectors, such as ``_mm_add_pi8``, have been
reimplemented to use the SSE2 instruction-set and XMM registers
unconditionally. These intrinsics are therefore *no longer
supported* if MMX is enabled without SSE2 -- either from targeting
CPUs from the Pentium-MMX through the Pentium 3, or explicitly via
passing arguments such as ``-mmmx -mno-sse2``. MMX assembly code
remains supported without requiring SSE2, including inside
inline-assembly.

- The compiler builtins such as ``__builtin_ia32_paddb`` which
formerly implemented the above MMX intrinsic functions have been
removed. Any uses of these removed functions should migrate to the
functions defined by the ``*mmintrin.h`` headers. A mapping can be
found in the file ``clang/www/builtins.py``.

Arm and AArch64 Support
^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Analysis/FlowSensitive/MapLattice.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ template <typename Key, typename ElementLattice> class MapLattice {

MapLattice() = default;

explicit MapLattice(Container C) { C = std::move(C); }
explicit MapLattice(Container C) : C{std::move(C)} {};

// The `bottom` element is the empty map.
static MapLattice bottom() { return MapLattice(); }
Expand Down
103 changes: 2 additions & 101 deletions clang/include/clang/Basic/BuiltinsX86.def
Original file line number Diff line number Diff line change
Expand Up @@ -47,107 +47,8 @@ TARGET_BUILTIN(__builtin_ia32_writeeflags_u32, "vUi", "n", "")
// doesn't work in the presence of re-declaration of _mm_prefetch for windows.
TARGET_BUILTIN(_mm_prefetch, "vcC*i", "nc", "mmx")
TARGET_BUILTIN(__builtin_ia32_emms, "v", "n", "mmx")
TARGET_BUILTIN(__builtin_ia32_paddb, "V8cV8cV8c", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_paddw, "V4sV4sV4s", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_paddd, "V2iV2iV2i", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_paddsb, "V8cV8cV8c", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_paddsw, "V4sV4sV4s", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_paddusb, "V8cV8cV8c", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_paddusw, "V4sV4sV4s", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_psubb, "V8cV8cV8c", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_psubw, "V4sV4sV4s", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_psubd, "V2iV2iV2i", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_psubsb, "V8cV8cV8c", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_psubsw, "V4sV4sV4s", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_psubusb, "V8cV8cV8c", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_psubusw, "V4sV4sV4s", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_pmulhw, "V4sV4sV4s", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_pmullw, "V4sV4sV4s", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_pmaddwd, "V2iV4sV4s", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_pand, "V1OiV1OiV1Oi", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_pandn, "V1OiV1OiV1Oi", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_por, "V1OiV1OiV1Oi", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_pxor, "V1OiV1OiV1Oi", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_psllw, "V4sV4sV1Oi", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_pslld, "V2iV2iV1Oi", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_psllq, "V1OiV1OiV1Oi", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_psrlw, "V4sV4sV1Oi", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_psrld, "V2iV2iV1Oi", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_psrlq, "V1OiV1OiV1Oi", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_psraw, "V4sV4sV1Oi", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_psrad, "V2iV2iV1Oi", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_psllwi, "V4sV4si", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_pslldi, "V2iV2ii", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_psllqi, "V1OiV1Oii", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_psrlwi, "V4sV4si", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_psrldi, "V2iV2ii", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_psrlqi, "V1OiV1Oii", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_psrawi, "V4sV4si", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_psradi, "V2iV2ii", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_packsswb, "V8cV4sV4s", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_packssdw, "V4sV2iV2i", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_packuswb, "V8cV4sV4s", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_punpckhbw, "V8cV8cV8c", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_punpckhwd, "V4sV4sV4s", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_punpckhdq, "V2iV2iV2i", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_punpcklbw, "V8cV8cV8c", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_punpcklwd, "V4sV4sV4s", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_punpckldq, "V2iV2iV2i", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_pcmpeqb, "V8cV8cV8c", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_pcmpeqw, "V4sV4sV4s", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_pcmpeqd, "V2iV2iV2i", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_pcmpgtb, "V8cV8cV8c", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_pcmpgtw, "V4sV4sV4s", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_pcmpgtd, "V2iV2iV2i", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_maskmovq, "vV8cV8cc*", "nV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_movntq, "vV1Oi*V1Oi", "nV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_vec_init_v2si, "V2iii", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_vec_init_v4hi, "V4sssss", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_vec_init_v8qi, "V8ccccccccc", "ncV:64:", "mmx")
TARGET_BUILTIN(__builtin_ia32_vec_ext_v2si, "iV2ii", "ncV:64:", "mmx")

// MMX2 (MMX+SSE) intrinsics
TARGET_BUILTIN(__builtin_ia32_cvtpi2ps, "V4fV4fV2i", "ncV:64:", "mmx,sse")
TARGET_BUILTIN(__builtin_ia32_cvtps2pi, "V2iV4f", "ncV:64:", "mmx,sse")
TARGET_BUILTIN(__builtin_ia32_cvttps2pi, "V2iV4f", "ncV:64:", "mmx,sse")
TARGET_BUILTIN(__builtin_ia32_pavgb, "V8cV8cV8c", "ncV:64:", "mmx,sse")
TARGET_BUILTIN(__builtin_ia32_pavgw, "V4sV4sV4s", "ncV:64:", "mmx,sse")
TARGET_BUILTIN(__builtin_ia32_pmaxsw, "V4sV4sV4s", "ncV:64:", "mmx,sse")
TARGET_BUILTIN(__builtin_ia32_pmaxub, "V8cV8cV8c", "ncV:64:", "mmx,sse")
TARGET_BUILTIN(__builtin_ia32_pminsw, "V4sV4sV4s", "ncV:64:", "mmx,sse")
TARGET_BUILTIN(__builtin_ia32_pminub, "V8cV8cV8c", "ncV:64:", "mmx,sse")
TARGET_BUILTIN(__builtin_ia32_pmovmskb, "iV8c", "ncV:64:", "mmx,sse")
TARGET_BUILTIN(__builtin_ia32_pmulhuw, "V4sV4sV4s", "ncV:64:", "mmx,sse")
TARGET_BUILTIN(__builtin_ia32_psadbw, "V4sV8cV8c", "ncV:64:", "mmx,sse")
TARGET_BUILTIN(__builtin_ia32_pshufw, "V4sV4sIc", "ncV:64:", "mmx,sse")
TARGET_BUILTIN(__builtin_ia32_vec_ext_v4hi, "iV4sIi", "ncV:64:", "mmx,sse")
TARGET_BUILTIN(__builtin_ia32_vec_set_v4hi, "V4sV4siIi", "ncV:64:", "mmx,sse")

// MMX+SSE2
TARGET_BUILTIN(__builtin_ia32_cvtpd2pi, "V2iV2d", "ncV:64:", "mmx,sse2")
TARGET_BUILTIN(__builtin_ia32_cvtpi2pd, "V2dV2i", "ncV:64:", "mmx,sse2")
TARGET_BUILTIN(__builtin_ia32_cvttpd2pi, "V2iV2d", "ncV:64:", "mmx,sse2")
TARGET_BUILTIN(__builtin_ia32_paddq, "V1OiV1OiV1Oi", "ncV:64:", "mmx,sse2")
TARGET_BUILTIN(__builtin_ia32_pmuludq, "V1OiV2iV2i", "ncV:64:", "mmx,sse2")
TARGET_BUILTIN(__builtin_ia32_psubq, "V1OiV1OiV1Oi", "ncV:64:", "mmx,sse2")

// MMX+SSSE3
TARGET_BUILTIN(__builtin_ia32_pabsb, "V8cV8c", "ncV:64:", "mmx,ssse3")
TARGET_BUILTIN(__builtin_ia32_pabsd, "V2iV2i", "ncV:64:", "mmx,ssse3")
TARGET_BUILTIN(__builtin_ia32_pabsw, "V4sV4s", "ncV:64:", "mmx,ssse3")
TARGET_BUILTIN(__builtin_ia32_palignr, "V8cV8cV8cIc", "ncV:64:", "mmx,ssse3")
TARGET_BUILTIN(__builtin_ia32_phaddd, "V2iV2iV2i", "ncV:64:", "mmx,ssse3")
TARGET_BUILTIN(__builtin_ia32_phaddsw, "V4sV4sV4s", "ncV:64:", "mmx,ssse3")
TARGET_BUILTIN(__builtin_ia32_phaddw, "V4sV4sV4s", "ncV:64:", "mmx,ssse3")
TARGET_BUILTIN(__builtin_ia32_phsubd, "V2iV2iV2i", "ncV:64:", "mmx,ssse3")
TARGET_BUILTIN(__builtin_ia32_phsubsw, "V4sV4sV4s", "ncV:64:", "mmx,ssse3")
TARGET_BUILTIN(__builtin_ia32_phsubw, "V4sV4sV4s", "ncV:64:", "mmx,ssse3")
TARGET_BUILTIN(__builtin_ia32_pmaddubsw, "V8cV8cV8c", "ncV:64:", "mmx,ssse3")
TARGET_BUILTIN(__builtin_ia32_pmulhrsw, "V4sV4sV4s", "ncV:64:", "mmx,ssse3")
TARGET_BUILTIN(__builtin_ia32_pshufb, "V8cV8cV8c", "ncV:64:", "mmx,ssse3")
TARGET_BUILTIN(__builtin_ia32_psignw, "V4sV4sV4s", "ncV:64:", "mmx,ssse3")
TARGET_BUILTIN(__builtin_ia32_psignb, "V8cV8cV8c", "ncV:64:", "mmx,ssse3")
TARGET_BUILTIN(__builtin_ia32_psignd, "V2iV2iV2i", "ncV:64:", "mmx,ssse3")
TARGET_BUILTIN(__builtin_ia32_vec_ext_v4hi, "sV4sIi", "ncV:64:", "sse")
TARGET_BUILTIN(__builtin_ia32_vec_set_v4hi, "V4sV4ssIi", "ncV:64:", "sse")

// SSE intrinsics.
TARGET_BUILTIN(__builtin_ia32_comieq, "iV4fV4f", "ncV:128:", "sse")
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -7534,6 +7534,9 @@ def code_completion_brief_comments : Flag<["-"], "code-completion-brief-comments
def code_completion_with_fixits : Flag<["-"], "code-completion-with-fixits">,
HelpText<"Include code completion results which require small fix-its.">,
MarshallingInfoFlag<FrontendOpts<"CodeCompleteOpts.IncludeFixIts">>;
def skip_function_bodies : Flag<["-"], "skip-function-bodies">,
HelpText<"Skip function bodies when possible">,
MarshallingInfoFlag<FrontendOpts<"SkipFunctionBodies">>;
def disable_free : Flag<["-"], "disable-free">,
HelpText<"Disable freeing of memory on exit">,
MarshallingInfoFlag<FrontendOpts<"DisableFree">>;
Expand Down
46 changes: 46 additions & 0 deletions clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,10 @@ class LocAsInteger : public NonLoc {
static bool classof(SVal V) { return V.getKind() == LocAsIntegerKind; }
};

/// The simplest example of a concrete compound value is nonloc::CompoundVal,
/// which represents a concrete r-value of an initializer-list or a string.
/// Internally, it contains an llvm::ImmutableList of SVal's stored inside the
/// literal.
class CompoundVal : public NonLoc {
friend class ento::SValBuilder;

Expand All @@ -346,6 +350,36 @@ class CompoundVal : public NonLoc {
static bool classof(SVal V) { return V.getKind() == CompoundValKind; }
};

/// While nonloc::CompoundVal covers a few simple use cases,
/// nonloc::LazyCompoundVal is a more performant and flexible way to represent
/// an rvalue of record type, so it shows up much more frequently during
/// analysis. This value is an r-value that represents a snapshot of any
/// structure "as a whole" at a given moment during the analysis. Such value is
/// already quite far from being referred to as "concrete", as many fields
/// inside it would be unknown or symbolic. nonloc::LazyCompoundVal operates by
/// storing two things:
/// * a reference to the TypedValueRegion being snapshotted (yes, it is always
/// typed), and also
/// * a reference to the whole Store object, obtained from the ProgramState in
/// which the nonloc::LazyCompoundVal was created.
///
/// Note that the old ProgramState and its Store is kept alive during the
/// analysis because these are immutable functional data structures and each new
/// Store value is represented as "earlier Store" + "additional binding".
///
/// Essentially, nonloc::LazyCompoundVal is a performance optimization for the
/// analyzer. Because Store is immutable, creating a nonloc::LazyCompoundVal is
/// a very cheap operation. Note that the Store contains all region bindings in
/// the program state, not only related to the region. Later, if necessary, such
/// value can be unpacked -- eg. when it is assigned to another variable.
///
/// If you ever need to inspect the contents of the LazyCompoundVal, you can use
/// StoreManager::iterBindings(). It'll iterate through all values in the Store,
/// but you're only interested in the ones that belong to
/// LazyCompoundVal::getRegion(); other bindings are immaterial.
///
/// NOTE: LazyCompoundVal::getRegion() itself is also immaterial (see the actual
/// method docs for details).
class LazyCompoundVal : public NonLoc {
friend class ento::SValBuilder;

Expand All @@ -363,6 +397,18 @@ class LazyCompoundVal : public NonLoc {
/// It might return null.
const void *getStore() const;

/// This function itself is immaterial. It is only an implementation detail.
/// LazyCompoundVal represents only the rvalue, the data (known or unknown)
/// that *was* stored in that region *at some point in the past*. The region
/// should not be used for any purpose other than figuring out what part of
/// the frozen Store you're interested in. The value does not represent the
/// *current* value of that region. Sometimes it may, but this should not be
/// relied upon. Instead, if you want to figure out what region it represents,
/// you typically need to see where you got it from in the first place. The
/// region is absolutely not analogous to the C++ "this" pointer. It is also
/// not a valid way to "materialize" the prvalue into a glvalue in C++,
/// because the region represents the *old* storage (sometimes very old), not
/// the *future* storage.
LLVM_ATTRIBUTE_RETURNS_NONNULL
const TypedValueRegion *getRegion() const;

Expand Down
3 changes: 2 additions & 1 deletion clang/lib/AST/Interp/ByteCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ using namespace clang::interp;
/// but that is not correct for our use cases.
static bool isUnevaluatedBuiltin(unsigned BuiltinID) {
return BuiltinID == Builtin::BI__builtin_classify_type ||
BuiltinID == Builtin::BI__builtin_os_log_format_buffer_size;
BuiltinID == Builtin::BI__builtin_os_log_format_buffer_size ||
BuiltinID == Builtin::BI__builtin_constant_p;
}

Function *ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) {
Expand Down
23 changes: 21 additions & 2 deletions clang/lib/AST/Interp/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ bool InitLink::emit(Compiler<Emitter> *Ctx, const Expr *E) const {
case K_Elem:
if (!Ctx->emitConstUint32(Offset, E))
return false;
return Ctx->emitArrayElemPtrUint32(E);
return Ctx->emitArrayElemPtrPopUint32(E);
default:
llvm_unreachable("Unhandled InitLink kind");
}
Expand Down Expand Up @@ -3256,6 +3256,9 @@ bool Compiler<Emitter>::visitInitializer(const Expr *E) {
if (E->containsErrors())
return this->emitError(E);

if (!this->checkLiteralType(E))
return false;

OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/false,
/*NewInitializing=*/true);
return this->Visit(E);
Expand Down Expand Up @@ -4156,7 +4159,8 @@ bool Compiler<Emitter>::VisitCXXThisExpr(const CXXThisExpr *E) {
if (InitStackActive && !InitStack.empty()) {
unsigned StartIndex = 0;
for (StartIndex = InitStack.size() - 1; StartIndex > 0; --StartIndex) {
if (InitStack[StartIndex].Kind != InitLink::K_Field)
if (InitStack[StartIndex].Kind != InitLink::K_Field &&
InitStack[StartIndex].Kind != InitLink::K_Elem)
break;
}

Expand Down Expand Up @@ -4697,6 +4701,17 @@ bool Compiler<Emitter>::emitLambdaStaticInvokerBody(const CXXMethodDecl *MD) {
return this->emitRetVoid(MD);
}

template <class Emitter>
bool Compiler<Emitter>::checkLiteralType(const Expr *E) {
if (Ctx.getLangOpts().CPlusPlus23)
return true;

if (!E->isPRValue() || E->getType()->isLiteralType(Ctx.getASTContext()))
return true;

return this->emitCheckLiteralType(E->getType().getTypePtr(), E);
}

template <class Emitter>
bool Compiler<Emitter>::visitFunc(const FunctionDecl *F) {
// Classify the return type.
Expand Down Expand Up @@ -5238,6 +5253,10 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) {
return false;
};

// DecompositionDecls are just proxies for us.
if (isa<DecompositionDecl>(VD))
return revisit(VD);

// Visit local const variables like normal.
if ((VD->hasGlobalStorage() || VD->isLocalVarDecl() ||
VD->isStaticDataMember()) &&
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/Interp/Compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,8 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
const QualType DerivedType);
bool emitLambdaStaticInvokerBody(const CXXMethodDecl *MD);

bool checkLiteralType(const Expr *E);

protected:
/// Variable to storage mapping.
llvm::DenseMap<const ValueDecl *, Scope::Local> Locals;
Expand Down
43 changes: 41 additions & 2 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1571,7 +1571,10 @@ inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
return false;
if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
return false;
S.Stk.push<Pointer>(Ptr.atField(Off));
const Pointer &Result = Ptr.atField(Off);
if (Result.isPastEnd())
return false;
S.Stk.push<Pointer>(Result);
return true;
}

Expand All @@ -1581,7 +1584,10 @@ inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off) {
return false;
if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
return false;
S.Stk.push<Pointer>(Ptr.atField(Off));
const Pointer &Result = Ptr.atField(Off);
if (Result.isPastEnd())
return false;
S.Stk.push<Pointer>(Result);
return true;
}

Expand Down Expand Up @@ -2964,6 +2970,39 @@ static inline bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm) {
BlockDesc, Source);
}

inline bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T) {
assert(T);
assert(!S.getLangOpts().CPlusPlus23);

// C++1y: A constant initializer for an object o [...] may also invoke
// constexpr constructors for o and its subobjects even if those objects
// are of non-literal class types.
//
// C++11 missed this detail for aggregates, so classes like this:
// struct foo_t { union { int i; volatile int j; } u; };
// are not (obviously) initializable like so:
// __attribute__((__require_constant_initialization__))
// static const foo_t x = {{0}};
// because "i" is a subobject with non-literal initialization (due to the
// volatile member of the union). See:
// http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1677
// Therefore, we use the C++1y behavior.

if (S.EvaluatingDecl)
return true;

if (S.Current->getFunction() && S.Current->getFunction()->isConstructor() &&
S.Current->getThis().getDeclDesc()->asDecl() == S.EvaluatingDecl)
return true;

const Expr *E = S.Current->getExpr(OpPC);
if (S.getLangOpts().CPlusPlus11)
S.FFDiag(E, diag::note_constexpr_nonliteral) << E->getType();
else
S.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);
return false;
}

//===----------------------------------------------------------------------===//
// Read opcode arguments
//===----------------------------------------------------------------------===//
Expand Down
74 changes: 74 additions & 0 deletions clang/lib/AST/Interp/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
//===----------------------------------------------------------------------===//
#include "../ExprConstShared.h"
#include "Boolean.h"
#include "Compiler.h"
#include "EvalEmitter.h"
#include "Interp.h"
#include "PrimType.h"
#include "clang/AST/OSLog.h"
Expand Down Expand Up @@ -1127,6 +1129,73 @@ static bool interp__builtin_ptrauth_string_discriminator(
return true;
}

// FIXME: This implementation is not complete.
// The Compiler instance we create cannot access the current stack frame, local
// variables, function parameters, etc. We also need protection from
// side-effects, fatal errors, etc.
static bool interp__builtin_constant_p(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func,
const CallExpr *Call) {
const Expr *Arg = Call->getArg(0);
QualType ArgType = Arg->getType();

auto returnInt = [&S, Call](bool Value) -> bool {
pushInteger(S, Value, Call->getType());
return true;
};

// __builtin_constant_p always has one operand. The rules which gcc follows
// are not precisely documented, but are as follows:
//
// - If the operand is of integral, floating, complex or enumeration type,
// and can be folded to a known value of that type, it returns 1.
// - If the operand can be folded to a pointer to the first character
// of a string literal (or such a pointer cast to an integral type)
// or to a null pointer or an integer cast to a pointer, it returns 1.
//
// Otherwise, it returns 0.
//
// FIXME: GCC also intends to return 1 for literals of aggregate types, but
// its support for this did not work prior to GCC 9 and is not yet well
// understood.
if (ArgType->isIntegralOrEnumerationType() || ArgType->isFloatingType() ||
ArgType->isAnyComplexType() || ArgType->isPointerType() ||
ArgType->isNullPtrType()) {
InterpStack Stk;
Compiler<EvalEmitter> C(S.Ctx, S.P, S, Stk);
auto Res = C.interpretExpr(Arg, /*ConvertResultToRValue=*/Arg->isGLValue());
if (Res.isInvalid()) {
C.cleanup();
Stk.clear();
}

const APValue &LV = Res.toAPValue();
if (!Res.isInvalid() && LV.isLValue()) {
APValue::LValueBase Base = LV.getLValueBase();
if (Base.isNull()) {
// A null base is acceptable.
return returnInt(true);
} else if (const auto *E = Base.dyn_cast<const Expr *>()) {
if (!isa<StringLiteral>(E))
return returnInt(false);
return returnInt(LV.getLValueOffset().isZero());
} else if (Base.is<TypeInfoLValue>()) {
// Surprisingly, GCC considers __builtin_constant_p(&typeid(int)) to
// evaluate to true.
return returnInt(true);
} else {
// Any other base is not constant enough for GCC.
return returnInt(false);
}
}

return returnInt(!Res.isInvalid() && !Res.empty());
}

return returnInt(false);
}

bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
const CallExpr *Call) {
const InterpFrame *Frame = S.Current;
Expand Down Expand Up @@ -1456,6 +1525,11 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
return false;
break;

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

default:
S.FFDiag(S.Current->getLocation(OpPC),
diag::note_invalid_subexpr_in_const_expr)
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/AST/Interp/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ def ArgVarDecl : ArgType { let Name = "const VarDecl*"; }
def ArgDesc : ArgType { let Name = "const Descriptor *"; }
def ArgPrimType : ArgType { let Name = "PrimType"; }
def ArgEnumDecl : ArgType { let Name = "const EnumDecl *"; }
def ArgTypePtr : ArgType { let Name = "const Type *"; }

//===----------------------------------------------------------------------===//
// Classes of types instructions operate on.
Expand Down Expand Up @@ -396,6 +397,10 @@ def CheckEnumValue : Opcode {
let HasGroup = 1;
}

def CheckLiteralType : Opcode {
let Args = [ArgTypePtr];
}

// [] -> [Value]
def GetGlobal : AccessOpcode;
def GetGlobalUnchecked : AccessOpcode;
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Basic/Sarif.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ static unsigned int adjustColumnPos(FullSourceLoc Loc,
/// @{

/// \internal
json::Object createMessage(StringRef Text) {
static json::Object createMessage(StringRef Text) {
return json::Object{{"text", Text.str()}};
}

Expand Down
18 changes: 3 additions & 15 deletions clang/lib/Basic/Targets/PPC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/MacroBuilder.h"
#include "clang/Basic/TargetBuiltins.h"
#include "llvm/TargetParser/PPCTargetParser.h"

using namespace clang;
using namespace clang::targets;
Expand Down Expand Up @@ -882,25 +883,12 @@ ArrayRef<TargetInfo::AddlRegName> PPCTargetInfo::getGCCAddlRegNames() const {
return llvm::ArrayRef(GCCAddlRegNames);
}

static constexpr llvm::StringLiteral ValidCPUNames[] = {
{"generic"}, {"440"}, {"450"}, {"601"}, {"602"},
{"603"}, {"603e"}, {"603ev"}, {"604"}, {"604e"},
{"620"}, {"630"}, {"g3"}, {"7400"}, {"g4"},
{"7450"}, {"g4+"}, {"750"}, {"8548"}, {"970"},
{"g5"}, {"a2"}, {"e500"}, {"e500mc"}, {"e5500"},
{"power3"}, {"pwr3"}, {"power4"}, {"pwr4"}, {"power5"},
{"pwr5"}, {"power5x"}, {"pwr5x"}, {"power6"}, {"pwr6"},
{"power6x"}, {"pwr6x"}, {"power7"}, {"pwr7"}, {"power8"},
{"pwr8"}, {"power9"}, {"pwr9"}, {"power10"}, {"pwr10"},
{"power11"}, {"pwr11"}, {"powerpc"}, {"ppc"}, {"ppc32"},
{"powerpc64"}, {"ppc64"}, {"powerpc64le"}, {"ppc64le"}, {"future"}};

bool PPCTargetInfo::isValidCPUName(StringRef Name) const {
return llvm::is_contained(ValidCPUNames, Name);
return llvm::PPC::isValidCPU(Name);
}

void PPCTargetInfo::fillValidCPUList(SmallVectorImpl<StringRef> &Values) const {
Values.append(std::begin(ValidCPUNames), std::end(ValidCPUNames));
llvm::PPC::fillValidCPUList(Values);
}

void PPCTargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts) {
Expand Down
8 changes: 2 additions & 6 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14523,12 +14523,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
// TODO: If we had a "freeze" IR instruction to generate a fixed undef
// value, we should use that here instead of a zero.
return llvm::Constant::getNullValue(ConvertType(E->getType()));
case X86::BI__builtin_ia32_vec_init_v8qi:
case X86::BI__builtin_ia32_vec_init_v4hi:
case X86::BI__builtin_ia32_vec_init_v2si:
return Builder.CreateBitCast(BuildVector(Ops),
llvm::Type::getX86_MMXTy(getLLVMContext()));
case X86::BI__builtin_ia32_vec_ext_v2si:
case X86::BI__builtin_ia32_vec_ext_v4hi:
case X86::BI__builtin_ia32_vec_ext_v16qi:
case X86::BI__builtin_ia32_vec_ext_v8hi:
case X86::BI__builtin_ia32_vec_ext_v4si:
Expand All @@ -14546,6 +14541,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
// Otherwise we could just do this in the header file.
return Builder.CreateExtractElement(Ops[0], Index);
}
case X86::BI__builtin_ia32_vec_set_v4hi:
case X86::BI__builtin_ia32_vec_set_v16qi:
case X86::BI__builtin_ia32_vec_set_v8hi:
case X86::BI__builtin_ia32_vec_set_v4si:
Expand Down
5 changes: 0 additions & 5 deletions clang/lib/CodeGen/CGOpenMPRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6047,11 +6047,6 @@ const Expr *CGOpenMPRuntime::getNumTeamsExprForTargetDirective(
MinTeamsVal = MaxTeamsVal = 0;
return nullptr;
}
if (isOpenMPParallelDirective(NestedDir->getDirectiveKind()) ||
isOpenMPSimdDirective(NestedDir->getDirectiveKind())) {
MinTeamsVal = MaxTeamsVal = 1;
return nullptr;
}
MinTeamsVal = MaxTeamsVal = 1;
return nullptr;
}
Expand Down
73 changes: 0 additions & 73 deletions clang/lib/Driver/ToolChains/Arch/PPC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,79 +20,6 @@ using namespace clang::driver::tools;
using namespace clang;
using namespace llvm::opt;

static std::string getPPCGenericTargetCPU(const llvm::Triple &T) {
// LLVM may default to generating code for the native CPU,
// but, like gcc, we default to a more generic option for
// each architecture. (except on AIX)
if (T.isOSAIX())
return "pwr7";
else if (T.getArch() == llvm::Triple::ppc64le)
return "ppc64le";
else if (T.getArch() == llvm::Triple::ppc64)
return "ppc64";
else
return "ppc";
}

static std::string normalizeCPUName(StringRef CPUName, const llvm::Triple &T) {
// Clang/LLVM does not actually support code generation
// for the 405 CPU. However, there are uses of this CPU ID
// in projects that previously used GCC and rely on Clang
// accepting it. Clang has always ignored it and passed the
// generic CPU ID to the back end.
if (CPUName == "generic" || CPUName == "405")
return getPPCGenericTargetCPU(T);

if (CPUName == "native") {
std::string CPU = std::string(llvm::sys::getHostCPUName());
if (!CPU.empty() && CPU != "generic")
return CPU;
else
return getPPCGenericTargetCPU(T);
}

return llvm::StringSwitch<const char *>(CPUName)
.Case("common", "generic")
.Case("440fp", "440")
.Case("630", "pwr3")
.Case("G3", "g3")
.Case("G4", "g4")
.Case("G4+", "g4+")
.Case("8548", "e500")
.Case("G5", "g5")
.Case("power3", "pwr3")
.Case("power4", "pwr4")
.Case("power5", "pwr5")
.Case("power5x", "pwr5x")
.Case("power6", "pwr6")
.Case("power6x", "pwr6x")
.Case("power7", "pwr7")
.Case("power8", "pwr8")
.Case("power9", "pwr9")
.Case("power10", "pwr10")
.Case("power11", "pwr11")
.Case("future", "future")
.Case("powerpc", "ppc")
.Case("powerpc64", "ppc64")
.Case("powerpc64le", "ppc64le")
.Default(CPUName.data());
}

/// Get the (LLVM) name of the PowerPC cpu we are tuning for.
std::string ppc::getPPCTuneCPU(const ArgList &Args, const llvm::Triple &T) {
if (Arg *A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ))
return normalizeCPUName(A->getValue(), T);
return getPPCGenericTargetCPU(T);
}

/// Get the (LLVM) name of the PowerPC cpu we are targeting.
std::string ppc::getPPCTargetCPU(const Driver &D, const ArgList &Args,
const llvm::Triple &T) {
if (Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ))
return normalizeCPUName(A->getValue(), T);
return getPPCGenericTargetCPU(T);
}

const char *ppc::getPPCAsmModeForCPU(StringRef Name) {
return llvm::StringSwitch<const char *>(Name)
.Case("pwr7", "-mpower7")
Expand Down
4 changes: 0 additions & 4 deletions clang/lib/Driver/ToolChains/Arch/PPC.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,6 @@ enum class ReadGOTPtrMode {

FloatABI getPPCFloatABI(const Driver &D, const llvm::opt::ArgList &Args);

std::string getPPCTargetCPU(const Driver &D, const llvm::opt::ArgList &Args,
const llvm::Triple &T);
std::string getPPCTuneCPU(const llvm::opt::ArgList &Args,
const llvm::Triple &T);
const char *getPPCAsmModeForCPU(StringRef Name);
ReadGOTPtrMode getPPCReadGOTPtrMode(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
Expand Down
14 changes: 11 additions & 3 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
#include "llvm/TargetParser/ARMTargetParserCommon.h"
#include "llvm/TargetParser/Host.h"
#include "llvm/TargetParser/LoongArchTargetParser.h"
#include "llvm/TargetParser/PPCTargetParser.h"
#include "llvm/TargetParser/RISCVISAInfo.h"
#include "llvm/TargetParser/RISCVTargetParser.h"
#include <cctype>
Expand Down Expand Up @@ -1512,6 +1513,10 @@ static void handlePAuthABI(const ArgList &DriverArgs, ArgStringList &CC1Args) {
options::OPT_fno_ptrauth_vtable_pointer_type_discrimination))
CC1Args.push_back("-fptrauth-vtable-pointer-type-discrimination");

if (!DriverArgs.hasArg(options::OPT_fptrauth_indirect_gotos,
options::OPT_fno_ptrauth_indirect_gotos))
CC1Args.push_back("-fptrauth-indirect-gotos");

if (!DriverArgs.hasArg(options::OPT_fptrauth_init_fini,
options::OPT_fno_ptrauth_init_fini))
CC1Args.push_back("-fptrauth-init-fini");
Expand Down Expand Up @@ -1839,6 +1844,9 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
Args.addOptInFlag(
CmdArgs, options::OPT_fptrauth_vtable_pointer_type_discrimination,
options::OPT_fno_ptrauth_vtable_pointer_type_discrimination);
Args.addOptInFlag(
CmdArgs, options::OPT_fptrauth_type_info_vtable_pointer_discrimination,
options::OPT_fno_ptrauth_type_info_vtable_pointer_discrimination);
Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_init_fini,
options::OPT_fno_ptrauth_init_fini);
Args.addOptInFlag(
Expand Down Expand Up @@ -2019,10 +2027,10 @@ void Clang::AddPPCTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
const Driver &D = getToolChain().getDriver();
const llvm::Triple &T = getToolChain().getTriple();
if (Args.getLastArg(options::OPT_mtune_EQ)) {
if (Arg *A = Args.getLastArg(options::OPT_mtune_EQ)) {
CmdArgs.push_back("-tune-cpu");
std::string CPU = ppc::getPPCTuneCPU(Args, T);
CmdArgs.push_back(Args.MakeArgString(CPU));
StringRef CPU = llvm::PPC::getNormalizedPPCTuneCPU(T, A->getValue());
CmdArgs.push_back(Args.MakeArgString(CPU.str()));
}

// Select the ABI to use.
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/Driver/ToolChains/CommonArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
#include "llvm/Support/VirtualFileSystem.h"
#include "llvm/Support/YAMLParser.h"
#include "llvm/TargetParser/Host.h"
#include "llvm/TargetParser/PPCTargetParser.h"
#include "llvm/TargetParser/TargetParser.h"
#include <optional>

Expand Down Expand Up @@ -634,7 +635,10 @@ std::string tools::getCPUName(const Driver &D, const ArgList &Args,
case llvm::Triple::ppcle:
case llvm::Triple::ppc64:
case llvm::Triple::ppc64le:
return ppc::getPPCTargetCPU(D, Args, T);
if (Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ))
return std::string(
llvm::PPC::getNormalizedPPCTargetCPU(T, A->getValue()));
return std::string(llvm::PPC::getNormalizedPPCTargetCPU(T));

case llvm::Triple::csky:
if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Driver/ToolChains/Cuda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,13 @@ void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA,
addLTOOptions(getToolChain(), Args, CmdArgs, Output, Inputs[0],
C.getDriver().getLTOMode() == LTOK_Thin);

// Forward the PTX features if the nvlink-wrapper needs it.
std::vector<StringRef> Features;
getNVPTXTargetFeatures(C.getDriver(), getToolChain().getTriple(), Args,
Features);
for (StringRef Feature : Features)
CmdArgs.append({"--feature", Args.MakeArgString(Feature)});

addGPULibraries(getToolChain(), Args, CmdArgs);

// Add paths for the default clang library path.
Expand Down
79 changes: 32 additions & 47 deletions clang/lib/Driver/ToolChains/PS4CPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,48 +152,36 @@ void tools::PS4cpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Output.getFilename());
}

const bool UseLTO = D.isUsingLTO();
const bool UseJMC =
Args.hasFlag(options::OPT_fjmc, options::OPT_fno_jmc, false);

const char *LTOArgs = "";
auto AddCodeGenFlag = [&](Twine Flag) {
auto AddLTOFlag = [&](Twine Flag) {
LTOArgs = Args.MakeArgString(Twine(LTOArgs) + " " + Flag);
};

if (UseLTO) {
// This tells LTO to perform JustMyCode instrumentation.
if (UseJMC)
AddCodeGenFlag("-enable-jmc-instrument");
// If the linker sees bitcode objects it will perform LTO. We can't tell
// whether or not that will be the case at this point. So, unconditionally
// pass LTO options to ensure proper codegen, metadata production, etc if
// LTO indeed occurs.
if (Args.hasFlag(options::OPT_funified_lto, options::OPT_fno_unified_lto,
true))
CmdArgs.push_back(D.getLTOMode() == LTOK_Thin ? "--lto=thin"
: "--lto=full");
if (UseJMC)
AddLTOFlag("-enable-jmc-instrument");

if (Arg *A = Args.getLastArg(options::OPT_fcrash_diagnostics_dir))
AddCodeGenFlag(Twine("-crash-diagnostics-dir=") + A->getValue());
if (Arg *A = Args.getLastArg(options::OPT_fcrash_diagnostics_dir))
AddLTOFlag(Twine("-crash-diagnostics-dir=") + A->getValue());

StringRef Parallelism = getLTOParallelism(Args, D);
if (!Parallelism.empty())
AddCodeGenFlag(Twine("-threads=") + Parallelism);
if (StringRef Threads = getLTOParallelism(Args, D); !Threads.empty())
AddLTOFlag(Twine("-threads=") + Threads);

const char *Prefix = nullptr;
if (D.getLTOMode() == LTOK_Thin)
Prefix = "-lto-thin-debug-options=";
else if (D.getLTOMode() == LTOK_Full)
Prefix = "-lto-debug-options=";
else
llvm_unreachable("new LTO mode?");

CmdArgs.push_back(Args.MakeArgString(Twine(Prefix) + LTOArgs));
}
CmdArgs.push_back(Args.MakeArgString(Twine("-lto-debug-options=") + LTOArgs));

if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs))
TC.addSanitizerArgs(Args, CmdArgs, "-l", "");

if (D.isUsingLTO() && Args.hasArg(options::OPT_funified_lto)) {
if (D.getLTOMode() == LTOK_Thin)
CmdArgs.push_back("--lto=thin");
else if (D.getLTOMode() == LTOK_Full)
CmdArgs.push_back("--lto=full");
}

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

Expand Down Expand Up @@ -259,37 +247,34 @@ void tools::PS5cpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Output.getFilename());
}

const bool UseLTO = D.isUsingLTO();
const bool UseJMC =
Args.hasFlag(options::OPT_fjmc, options::OPT_fno_jmc, false);

auto AddCodeGenFlag = [&](Twine Flag) {
auto AddLTOFlag = [&](Twine Flag) {
CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=") + Flag));
};

if (UseLTO) {
// This tells LTO to perform JustMyCode instrumentation.
if (UseJMC)
AddCodeGenFlag("-enable-jmc-instrument");
// If the linker sees bitcode objects it will perform LTO. We can't tell
// whether or not that will be the case at this point. So, unconditionally
// pass LTO options to ensure proper codegen, metadata production, etc if
// LTO indeed occurs.
if (Args.hasFlag(options::OPT_funified_lto, options::OPT_fno_unified_lto,
true))
CmdArgs.push_back(D.getLTOMode() == LTOK_Thin ? "--lto=thin"
: "--lto=full");

if (Arg *A = Args.getLastArg(options::OPT_fcrash_diagnostics_dir))
AddCodeGenFlag(Twine("-crash-diagnostics-dir=") + A->getValue());
if (UseJMC)
AddLTOFlag("-enable-jmc-instrument");

StringRef Parallelism = getLTOParallelism(Args, D);
if (!Parallelism.empty())
CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=jobs=") + Parallelism));
}
if (Arg *A = Args.getLastArg(options::OPT_fcrash_diagnostics_dir))
AddLTOFlag(Twine("-crash-diagnostics-dir=") + A->getValue());

if (StringRef Jobs = getLTOParallelism(Args, D); !Jobs.empty())
AddLTOFlag(Twine("jobs=") + Jobs);

if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs))
TC.addSanitizerArgs(Args, CmdArgs, "-l", "");

if (D.isUsingLTO() && Args.hasArg(options::OPT_funified_lto)) {
if (D.getLTOMode() == LTOK_Thin)
CmdArgs.push_back("--lto=thin");
else if (D.getLTOMode() == LTOK_Full)
CmdArgs.push_back("--lto=full");
}

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

Expand Down
38 changes: 35 additions & 3 deletions clang/lib/Format/ContinuationIndenter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -803,6 +803,37 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
return !Tok.Previous->isOneOf(TT_CastRParen, tok::kw_for, tok::kw_while,
tok::kw_switch);
};
auto IsFunctionCallParen = [](const FormatToken &Tok) {
return Tok.is(tok::l_paren) && Tok.ParameterCount > 0 && Tok.Previous &&
Tok.Previous->is(tok::identifier);
};
const auto IsInTemplateString = [this](const FormatToken &Tok) {
if (!Style.isJavaScript())
return false;
for (const auto *Prev = &Tok; Prev; Prev = Prev->Previous) {
if (Prev->is(TT_TemplateString) && Prev->opensScope())
return true;
if (Prev->is(TT_TemplateString) && Prev->closesScope())
break;
}
return false;
};
// Identifies simple (no expression) one-argument function calls.
const auto IsSimpleFunction = [&](const FormatToken &Tok) {
if (!Tok.FakeLParens.empty() && Tok.FakeLParens.back() > prec::Unknown)
return false;
const auto *Previous = Tok.Previous;
if (!Previous || (!Previous->isOneOf(TT_FunctionDeclarationLParen,
TT_LambdaDefinitionLParen) &&
!IsFunctionCallParen(*Previous))) {
return true;
}
if (IsOpeningBracket(Tok) || IsInTemplateString(Tok))
return true;
const auto *Next = Tok.Next;
return !Next || Next->isMemberAccess() ||
Next->is(TT_FunctionDeclarationLParen) || IsFunctionCallParen(*Next);
};
if ((Style.AlignAfterOpenBracket == FormatStyle::BAS_AlwaysBreak ||
Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent) &&
IsOpeningBracket(Previous) && State.Column > getNewLineColumn(State) &&
Expand All @@ -813,10 +844,10 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
// caaaaaaaaaaaall(
// caaaaaaaaaaaall(
// caaaaaaaaaaaaaaaaaaaaaaall(aaaaaaaaaaaaaa, aaaaaaaaa))));
Current.FakeLParens.size() > 0 &&
Current.FakeLParens.back() > prec::Unknown) {
!IsSimpleFunction(Current)) {
CurrentState.NoLineBreak = true;
}

if (Previous.is(TT_TemplateString) && Previous.opensScope())
CurrentState.NoLineBreak = true;

Expand All @@ -831,7 +862,8 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
Previous.isNot(TT_TableGenDAGArgOpenerToBreak) &&
!(Current.MacroParent && Previous.MacroParent) &&
(Current.isNot(TT_LineComment) ||
Previous.isOneOf(BK_BracedInit, TT_VerilogMultiLineListLParen))) {
Previous.isOneOf(BK_BracedInit, TT_VerilogMultiLineListLParen)) &&
!IsInTemplateString(Current)) {
CurrentState.Indent = State.Column + Spaces;
CurrentState.IsAligned = true;
}
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Format/FormatToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ namespace format {
TYPE(JsTypeColon) \
TYPE(JsTypeOperator) \
TYPE(JsTypeOptionalQuestion) \
TYPE(LambdaDefinitionLParen) \
TYPE(LambdaLBrace) \
TYPE(LambdaLSquare) \
TYPE(LeadingJavaAnnotation) \
Expand Down
27 changes: 13 additions & 14 deletions clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ static bool canBeObjCSelectorComponent(const FormatToken &Tok) {

/// With `Left` being '(', check if we're at either `[...](` or
/// `[...]<...>(`, where the [ opens a lambda capture list.
// FIXME: this doesn't cover attributes/constraints before the l_paren.
static bool isLambdaParameterList(const FormatToken *Left) {
// Skip <...> if present.
if (Left->Previous && Left->Previous->is(tok::greater) &&
Expand Down Expand Up @@ -365,13 +366,18 @@ class AnnotatingParser {
Contexts.back().IsExpression = false;
} else if (isLambdaParameterList(&OpeningParen)) {
// This is a parameter list of a lambda expression.
OpeningParen.setType(TT_LambdaDefinitionLParen);
Contexts.back().IsExpression = false;
} else if (OpeningParen.is(TT_RequiresExpressionLParen)) {
Contexts.back().IsExpression = false;
} else if (OpeningParen.Previous &&
OpeningParen.Previous->is(tok::kw__Generic)) {
Contexts.back().ContextType = Context::C11GenericSelection;
Contexts.back().IsExpression = true;
} else if (Line.InPPDirective &&
(!OpeningParen.Previous ||
OpeningParen.Previous->isNot(tok::identifier))) {
Contexts.back().IsExpression = true;
} else if (Contexts[Contexts.size() - 2].CaretFound) {
// This is the parameter list of an ObjC block.
Contexts.back().IsExpression = false;
Expand All @@ -384,20 +390,7 @@ class AnnotatingParser {
OpeningParen.Previous->MatchingParen->isOneOf(
TT_ObjCBlockLParen, TT_FunctionTypeLParen)) {
Contexts.back().IsExpression = false;
} else if (Line.InPPDirective) {
auto IsExpr = [&OpeningParen] {
const auto *Tok = OpeningParen.Previous;
if (!Tok || Tok->isNot(tok::identifier))
return true;
Tok = Tok->Previous;
while (Tok && Tok->endsSequence(tok::coloncolon, tok::identifier)) {
assert(Tok->Previous);
Tok = Tok->Previous->Previous;
}
return !Tok || !Tok->Tok.getIdentifierInfo();
};
Contexts.back().IsExpression = IsExpr();
} else if (!Line.MustBeDeclaration) {
} else if (!Line.MustBeDeclaration && !Line.InPPDirective) {
bool IsForOrCatch =
OpeningParen.Previous &&
OpeningParen.Previous->isOneOf(tok::kw_for, tok::kw_catch);
Expand Down Expand Up @@ -6205,6 +6198,12 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
return !(Previous && (Previous->is(tok::kw_for) || Previous->isIf()));
}

if (Left.isOneOf(tok::r_paren, TT_TrailingAnnotation) &&
Right.is(TT_TrailingAnnotation) &&
Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent) {
return false;
}

// Allow breaking after a trailing annotation, e.g. after a method
// declaration.
if (Left.is(TT_TrailingAnnotation)) {
Expand Down
41 changes: 22 additions & 19 deletions clang/lib/Headers/emmintrin.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,12 @@ typedef __bf16 __m128bh __attribute__((__vector_size__(16), __aligned__(16)));
#define __DEFAULT_FN_ATTRS \
__attribute__((__always_inline__, __nodebug__, \
__target__("sse2,no-evex512"), __min_vector_width__(128)))
#define __DEFAULT_FN_ATTRS_MMX \
__attribute__((__always_inline__, __nodebug__, \
__target__("mmx,sse2,no-evex512"), __min_vector_width__(64)))

#define __trunc64(x) \
(__m64) __builtin_shufflevector((__v2di)(x), __extension__(__v2di){}, 0)
#define __anyext128(x) \
(__m128i) __builtin_shufflevector((__v2si)(x), __extension__(__v2si){}, 0, \
1, -1, -1)

/// Adds lower double-precision values in both operands and returns the
/// sum in the lower 64 bits of the result. The upper 64 bits of the result
Expand Down Expand Up @@ -1486,8 +1489,8 @@ static __inline__ int __DEFAULT_FN_ATTRS _mm_cvttsd_si32(__m128d __a) {
/// \param __a
/// A 128-bit vector of [2 x double].
/// \returns A 64-bit vector of [2 x i32] containing the converted values.
static __inline__ __m64 __DEFAULT_FN_ATTRS_MMX _mm_cvtpd_pi32(__m128d __a) {
return (__m64)__builtin_ia32_cvtpd2pi((__v2df)__a);
static __inline__ __m64 __DEFAULT_FN_ATTRS _mm_cvtpd_pi32(__m128d __a) {
return __trunc64(__builtin_ia32_cvtpd2dq((__v2df)__a));
}

/// Converts the two double-precision floating-point elements of a
Expand All @@ -1505,8 +1508,8 @@ static __inline__ __m64 __DEFAULT_FN_ATTRS_MMX _mm_cvtpd_pi32(__m128d __a) {
/// \param __a
/// A 128-bit vector of [2 x double].
/// \returns A 64-bit vector of [2 x i32] containing the converted values.
static __inline__ __m64 __DEFAULT_FN_ATTRS_MMX _mm_cvttpd_pi32(__m128d __a) {
return (__m64)__builtin_ia32_cvttpd2pi((__v2df)__a);
static __inline__ __m64 __DEFAULT_FN_ATTRS _mm_cvttpd_pi32(__m128d __a) {
return __trunc64(__builtin_ia32_cvttpd2dq((__v2df)__a));
}

/// Converts the two signed 32-bit integer elements of a 64-bit vector of
Expand All @@ -1520,8 +1523,8 @@ static __inline__ __m64 __DEFAULT_FN_ATTRS_MMX _mm_cvttpd_pi32(__m128d __a) {
/// \param __a
/// A 64-bit vector of [2 x i32].
/// \returns A 128-bit vector of [2 x double] containing the converted values.
static __inline__ __m128d __DEFAULT_FN_ATTRS_MMX _mm_cvtpi32_pd(__m64 __a) {
return __builtin_ia32_cvtpi2pd((__v2si)__a);
static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_cvtpi32_pd(__m64 __a) {
return (__m128d) __builtin_convertvector((__v2si)__a, __v2df);
}

/// Returns the low-order element of a 128-bit vector of [2 x double] as
Expand Down Expand Up @@ -2108,9 +2111,8 @@ static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_add_epi32(__m128i __a,
/// \param __b
/// A 64-bit integer.
/// \returns A 64-bit integer containing the sum of both parameters.
static __inline__ __m64 __DEFAULT_FN_ATTRS_MMX _mm_add_si64(__m64 __a,
__m64 __b) {
return (__m64)__builtin_ia32_paddq((__v1di)__a, (__v1di)__b);
static __inline__ __m64 __DEFAULT_FN_ATTRS _mm_add_si64(__m64 __a, __m64 __b) {
return (__m64)(((unsigned long long)__a) + ((unsigned long long)__b));
}

/// Adds the corresponding elements of two 128-bit vectors of [2 x i64],
Expand Down Expand Up @@ -2431,9 +2433,9 @@ static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_mullo_epi16(__m128i __a,
/// \param __b
/// A 64-bit integer containing one of the source operands.
/// \returns A 64-bit integer vector containing the product of both operands.
static __inline__ __m64 __DEFAULT_FN_ATTRS_MMX _mm_mul_su32(__m64 __a,
__m64 __b) {
return __builtin_ia32_pmuludq((__v2si)__a, (__v2si)__b);
static __inline__ __m64 __DEFAULT_FN_ATTRS _mm_mul_su32(__m64 __a, __m64 __b) {
return __trunc64(__builtin_ia32_pmuludq128((__v4si)__anyext128(__a),
(__v4si)__anyext128(__b)));
}

/// Multiplies 32-bit unsigned integer values contained in the lower
Expand Down Expand Up @@ -2539,9 +2541,8 @@ static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_sub_epi32(__m128i __a,
/// A 64-bit integer vector containing the subtrahend.
/// \returns A 64-bit integer vector containing the difference of the values in
/// the operands.
static __inline__ __m64 __DEFAULT_FN_ATTRS_MMX _mm_sub_si64(__m64 __a,
__m64 __b) {
return (__m64)__builtin_ia32_psubq((__v1di)__a, (__v1di)__b);
static __inline__ __m64 __DEFAULT_FN_ATTRS _mm_sub_si64(__m64 __a, __m64 __b) {
return (__m64)((unsigned long long)__a - (unsigned long long)__b);
}

/// Subtracts the corresponding elements of two [2 x i64] vectors.
Expand Down Expand Up @@ -4889,8 +4890,10 @@ void _mm_pause(void);
#if defined(__cplusplus)
} // extern "C"
#endif

#undef __anyext128
#undef __trunc64
#undef __DEFAULT_FN_ATTRS
#undef __DEFAULT_FN_ATTRS_MMX

#define _MM_SHUFFLE2(x, y) (((x) << 1) | (y))

Expand Down
308 changes: 180 additions & 128 deletions clang/lib/Headers/mmintrin.h

Large diffs are not rendered by default.

96 changes: 58 additions & 38 deletions clang/lib/Headers/tmmintrin.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@
/* Define the default attributes for the functions in this file. */
#define __DEFAULT_FN_ATTRS \
__attribute__((__always_inline__, __nodebug__, \
__target__("ssse3,no-evex512"), __min_vector_width__(64)))
#define __DEFAULT_FN_ATTRS_MMX \
__attribute__((__always_inline__, __nodebug__, \
__target__("mmx,ssse3,no-evex512"), \
__min_vector_width__(64)))
__target__("ssse3,no-evex512"), __min_vector_width__(128)))

#define __trunc64(x) \
(__m64) __builtin_shufflevector((__v2di)(x), __extension__(__v2di){}, 0)
#define __anyext128(x) \
(__m128i) __builtin_shufflevector((__v2si)(x), __extension__(__v2si){}, 0, \
1, -1, -1)

/// Computes the absolute value of each of the packed 8-bit signed
/// integers in the source operand and stores the 8-bit unsigned integer
Expand All @@ -37,10 +39,10 @@
/// A 64-bit vector of [8 x i8].
/// \returns A 64-bit integer vector containing the absolute values of the
/// elements in the operand.
static __inline__ __m64 __DEFAULT_FN_ATTRS_MMX
static __inline__ __m64 __DEFAULT_FN_ATTRS
_mm_abs_pi8(__m64 __a)
{
return (__m64)__builtin_ia32_pabsb((__v8qi)__a);
return (__m64)__builtin_elementwise_abs((__v8qs)__a);
}

/// Computes the absolute value of each of the packed 8-bit signed
Expand Down Expand Up @@ -73,10 +75,10 @@ _mm_abs_epi8(__m128i __a)
/// A 64-bit vector of [4 x i16].
/// \returns A 64-bit integer vector containing the absolute values of the
/// elements in the operand.
static __inline__ __m64 __DEFAULT_FN_ATTRS_MMX
static __inline__ __m64 __DEFAULT_FN_ATTRS
_mm_abs_pi16(__m64 __a)
{
return (__m64)__builtin_ia32_pabsw((__v4hi)__a);
return (__m64)__builtin_elementwise_abs((__v4hi)__a);
}

/// Computes the absolute value of each of the packed 16-bit signed
Expand Down Expand Up @@ -109,10 +111,10 @@ _mm_abs_epi16(__m128i __a)
/// A 64-bit vector of [2 x i32].
/// \returns A 64-bit integer vector containing the absolute values of the
/// elements in the operand.
static __inline__ __m64 __DEFAULT_FN_ATTRS_MMX
static __inline__ __m64 __DEFAULT_FN_ATTRS
_mm_abs_pi32(__m64 __a)
{
return (__m64)__builtin_ia32_pabsd((__v2si)__a);
return (__m64)__builtin_elementwise_abs((__v2si)__a);
}

/// Computes the absolute value of each of the packed 32-bit signed
Expand Down Expand Up @@ -177,7 +179,10 @@ _mm_abs_epi32(__m128i __a)
/// \returns A 64-bit integer vector containing the concatenated right-shifted
/// value.
#define _mm_alignr_pi8(a, b, n) \
((__m64)__builtin_ia32_palignr((__v8qi)(__m64)(a), (__v8qi)(__m64)(b), (n)))
((__m64)__builtin_shufflevector( \
__builtin_ia32_psrldqi128_byteshift( \
__builtin_shufflevector((__v1di)(a), (__v1di)(b), 1, 0), \
(n)), __extension__ (__v2di){}, 0))

/// Horizontally adds the adjacent pairs of values contained in 2 packed
/// 128-bit vectors of [8 x i16].
Expand Down Expand Up @@ -242,10 +247,11 @@ _mm_hadd_epi32(__m128i __a, __m128i __b)
/// destination.
/// \returns A 64-bit vector of [4 x i16] containing the horizontal sums of both
/// operands.
static __inline__ __m64 __DEFAULT_FN_ATTRS_MMX
static __inline__ __m64 __DEFAULT_FN_ATTRS
_mm_hadd_pi16(__m64 __a, __m64 __b)
{
return (__m64)__builtin_ia32_phaddw((__v4hi)__a, (__v4hi)__b);
return __trunc64(__builtin_ia32_phaddw128(
(__v8hi)__builtin_shufflevector(__a, __b, 0, 1), (__v8hi){}));
}

/// Horizontally adds the adjacent pairs of values contained in 2 packed
Expand All @@ -265,10 +271,11 @@ _mm_hadd_pi16(__m64 __a, __m64 __b)
/// destination.
/// \returns A 64-bit vector of [2 x i32] containing the horizontal sums of both
/// operands.
static __inline__ __m64 __DEFAULT_FN_ATTRS_MMX
static __inline__ __m64 __DEFAULT_FN_ATTRS
_mm_hadd_pi32(__m64 __a, __m64 __b)
{
return (__m64)__builtin_ia32_phaddd((__v2si)__a, (__v2si)__b);
return __trunc64(__builtin_ia32_phaddd128(
(__v4si)__builtin_shufflevector(__a, __b, 0, 1), (__v4si){}));
}

/// Horizontally adds, with saturation, the adjacent pairs of values contained
Expand Down Expand Up @@ -317,10 +324,11 @@ _mm_hadds_epi16(__m128i __a, __m128i __b)
/// destination.
/// \returns A 64-bit vector of [4 x i16] containing the horizontal saturated
/// sums of both operands.
static __inline__ __m64 __DEFAULT_FN_ATTRS_MMX
static __inline__ __m64 __DEFAULT_FN_ATTRS
_mm_hadds_pi16(__m64 __a, __m64 __b)
{
return (__m64)__builtin_ia32_phaddsw((__v4hi)__a, (__v4hi)__b);
return __trunc64(__builtin_ia32_phaddsw128(
(__v8hi)__builtin_shufflevector(__a, __b, 0, 1), (__v8hi){}));
}

/// Horizontally subtracts the adjacent pairs of values contained in 2
Expand Down Expand Up @@ -386,10 +394,11 @@ _mm_hsub_epi32(__m128i __a, __m128i __b)
/// the destination.
/// \returns A 64-bit vector of [4 x i16] containing the horizontal differences
/// of both operands.
static __inline__ __m64 __DEFAULT_FN_ATTRS_MMX
static __inline__ __m64 __DEFAULT_FN_ATTRS
_mm_hsub_pi16(__m64 __a, __m64 __b)
{
return (__m64)__builtin_ia32_phsubw((__v4hi)__a, (__v4hi)__b);
return __trunc64(__builtin_ia32_phsubw128(
(__v8hi)__builtin_shufflevector(__a, __b, 0, 1), (__v8hi){}));
}

/// Horizontally subtracts the adjacent pairs of values contained in 2
Expand All @@ -409,10 +418,11 @@ _mm_hsub_pi16(__m64 __a, __m64 __b)
/// the destination.
/// \returns A 64-bit vector of [2 x i32] containing the horizontal differences
/// of both operands.
static __inline__ __m64 __DEFAULT_FN_ATTRS_MMX
static __inline__ __m64 __DEFAULT_FN_ATTRS
_mm_hsub_pi32(__m64 __a, __m64 __b)
{
return (__m64)__builtin_ia32_phsubd((__v2si)__a, (__v2si)__b);
return __trunc64(__builtin_ia32_phsubd128(
(__v4si)__builtin_shufflevector(__a, __b, 0, 1), (__v4si){}));
}

/// Horizontally subtracts, with saturation, the adjacent pairs of values
Expand Down Expand Up @@ -461,10 +471,11 @@ _mm_hsubs_epi16(__m128i __a, __m128i __b)
/// the destination.
/// \returns A 64-bit vector of [4 x i16] containing the horizontal saturated
/// differences of both operands.
static __inline__ __m64 __DEFAULT_FN_ATTRS_MMX
static __inline__ __m64 __DEFAULT_FN_ATTRS
_mm_hsubs_pi16(__m64 __a, __m64 __b)
{
return (__m64)__builtin_ia32_phsubsw((__v4hi)__a, (__v4hi)__b);
return __trunc64(__builtin_ia32_phsubsw128(
(__v8hi)__builtin_shufflevector(__a, __b, 0, 1), (__v8hi){}));
}

/// Multiplies corresponding pairs of packed 8-bit unsigned integer
Expand Down Expand Up @@ -525,10 +536,11 @@ _mm_maddubs_epi16(__m128i __a, __m128i __b)
/// \a R1 := (\a __a2 * \a __b2) + (\a __a3 * \a __b3) \n
/// \a R2 := (\a __a4 * \a __b4) + (\a __a5 * \a __b5) \n
/// \a R3 := (\a __a6 * \a __b6) + (\a __a7 * \a __b7)
static __inline__ __m64 __DEFAULT_FN_ATTRS_MMX
static __inline__ __m64 __DEFAULT_FN_ATTRS
_mm_maddubs_pi16(__m64 __a, __m64 __b)
{
return (__m64)__builtin_ia32_pmaddubsw((__v8qi)__a, (__v8qi)__b);
return __trunc64(__builtin_ia32_pmaddubsw128((__v16qi)__anyext128(__a),
(__v16qi)__anyext128(__b)));
}

/// Multiplies packed 16-bit signed integer values, truncates the 32-bit
Expand Down Expand Up @@ -565,10 +577,11 @@ _mm_mulhrs_epi16(__m128i __a, __m128i __b)
/// A 64-bit vector of [4 x i16] containing one of the source operands.
/// \returns A 64-bit vector of [4 x i16] containing the rounded and scaled
/// products of both operands.
static __inline__ __m64 __DEFAULT_FN_ATTRS_MMX
static __inline__ __m64 __DEFAULT_FN_ATTRS
_mm_mulhrs_pi16(__m64 __a, __m64 __b)
{
return (__m64)__builtin_ia32_pmulhrsw((__v4hi)__a, (__v4hi)__b);
return __trunc64(__builtin_ia32_pmulhrsw128((__v8hi)__anyext128(__a),
(__v8hi)__anyext128(__b)));
}

/// Copies the 8-bit integers from a 128-bit integer vector to the
Expand Down Expand Up @@ -614,12 +627,15 @@ _mm_shuffle_epi8(__m128i __a, __m128i __b)
/// 1: Clear the corresponding byte in the destination. \n
/// 0: Copy the selected source byte to the corresponding byte in the
/// destination. \n
/// Bits [3:0] select the source byte to be copied.
/// Bits [2:0] select the source byte to be copied.
/// \returns A 64-bit integer vector containing the copied or cleared values.
static __inline__ __m64 __DEFAULT_FN_ATTRS_MMX
static __inline__ __m64 __DEFAULT_FN_ATTRS
_mm_shuffle_pi8(__m64 __a, __m64 __b)
{
return (__m64)__builtin_ia32_pshufb((__v8qi)__a, (__v8qi)__b);
return __trunc64(__builtin_ia32_pshufb128(
(__v16qi)__builtin_shufflevector(
(__v2si)(__a), __extension__ (__v2si){}, 0, 1, 0, 1),
(__v16qi)__anyext128(__b)));
}

/// For each 8-bit integer in the first source operand, perform one of
Expand Down Expand Up @@ -720,10 +736,11 @@ _mm_sign_epi32(__m128i __a, __m128i __b)
/// A 64-bit integer vector containing control bytes corresponding to
/// positions in the destination.
/// \returns A 64-bit integer vector containing the resultant values.
static __inline__ __m64 __DEFAULT_FN_ATTRS_MMX
static __inline__ __m64 __DEFAULT_FN_ATTRS
_mm_sign_pi8(__m64 __a, __m64 __b)
{
return (__m64)__builtin_ia32_psignb((__v8qi)__a, (__v8qi)__b);
return __trunc64(__builtin_ia32_psignb128((__v16qi)__anyext128(__a),
(__v16qi)__anyext128(__b)));
}

/// For each 16-bit integer in the first source operand, perform one of
Expand All @@ -746,10 +763,11 @@ _mm_sign_pi8(__m64 __a, __m64 __b)
/// A 64-bit integer vector containing control words corresponding to
/// positions in the destination.
/// \returns A 64-bit integer vector containing the resultant values.
static __inline__ __m64 __DEFAULT_FN_ATTRS_MMX
static __inline__ __m64 __DEFAULT_FN_ATTRS
_mm_sign_pi16(__m64 __a, __m64 __b)
{
return (__m64)__builtin_ia32_psignw((__v4hi)__a, (__v4hi)__b);
return __trunc64(__builtin_ia32_psignw128((__v8hi)__anyext128(__a),
(__v8hi)__anyext128(__b)));
}

/// For each 32-bit integer in the first source operand, perform one of
Expand All @@ -772,13 +790,15 @@ _mm_sign_pi16(__m64 __a, __m64 __b)
/// A 64-bit integer vector containing two control doublewords corresponding
/// to positions in the destination.
/// \returns A 64-bit integer vector containing the resultant values.
static __inline__ __m64 __DEFAULT_FN_ATTRS_MMX
static __inline__ __m64 __DEFAULT_FN_ATTRS
_mm_sign_pi32(__m64 __a, __m64 __b)
{
return (__m64)__builtin_ia32_psignd((__v2si)__a, (__v2si)__b);
return __trunc64(__builtin_ia32_psignd128((__v4si)__anyext128(__a),
(__v4si)__anyext128(__b)));
}

#undef __anyext128
#undef __trunc64
#undef __DEFAULT_FN_ATTRS
#undef __DEFAULT_FN_ATTRS_MMX

#endif /* __TMMINTRIN_H */
193 changes: 97 additions & 96 deletions clang/lib/Headers/xmmintrin.h

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion clang/lib/Parse/ParseExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,9 @@ class CastExpressionIdValidator final : public CorrectionCandidateCallback {
bool Parser::isRevertibleTypeTrait(const IdentifierInfo *II,
tok::TokenKind *Kind) {
if (RevertibleTypeTraits.empty()) {
// Revertible type trait is a feature for backwards compatibility with older
// standard libraries that declare their own structs with the same name as
// the builtins listed below. New builtins should NOT be added to this list.
#define RTT_JOIN(X, Y) X##Y
#define REVERTIBLE_TYPE_TRAIT(Name) \
RevertibleTypeTraits[PP.getIdentifierInfo(#Name)] = RTT_JOIN(tok::kw_, Name)
Expand Down Expand Up @@ -790,7 +793,6 @@ bool Parser::isRevertibleTypeTrait(const IdentifierInfo *II,
REVERTIBLE_TYPE_TRAIT(__is_fundamental);
REVERTIBLE_TYPE_TRAIT(__is_integral);
REVERTIBLE_TYPE_TRAIT(__is_interface_class);
REVERTIBLE_TYPE_TRAIT(__is_layout_compatible);
REVERTIBLE_TYPE_TRAIT(__is_literal);
REVERTIBLE_TYPE_TRAIT(__is_lvalue_expr);
REVERTIBLE_TYPE_TRAIT(__is_lvalue_reference);
Expand Down
44 changes: 35 additions & 9 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8202,20 +8202,46 @@ static bool IsStdFunction(const FunctionDecl *FDecl,
return true;
}

enum class MathCheck { NaN, Inf };
static bool IsInfOrNanFunction(StringRef calleeName, MathCheck Check) {
auto MatchesAny = [&](std::initializer_list<llvm::StringRef> names) {
return std::any_of(names.begin(), names.end(), [&](llvm::StringRef name) {
return calleeName == name;
});
};

switch (Check) {
case MathCheck::NaN:
return MatchesAny({"__builtin_nan", "__builtin_nanf", "__builtin_nanl",
"__builtin_nanf16", "__builtin_nanf128"});
case MathCheck::Inf:
return MatchesAny({"__builtin_inf", "__builtin_inff", "__builtin_infl",
"__builtin_inff16", "__builtin_inff128"});
}
llvm_unreachable("unknown MathCheck");
}

void Sema::CheckInfNaNFunction(const CallExpr *Call,
const FunctionDecl *FDecl) {
FPOptions FPO = Call->getFPFeaturesInEffect(getLangOpts());
if ((IsStdFunction(FDecl, "isnan") || IsStdFunction(FDecl, "isunordered") ||
(Call->getBuiltinCallee() == Builtin::BI__builtin_nanf)) &&
FPO.getNoHonorNaNs())
bool HasIdentifier = FDecl->getIdentifier() != nullptr;
bool IsNaNOrIsUnordered =
IsStdFunction(FDecl, "isnan") || IsStdFunction(FDecl, "isunordered");
bool IsSpecialNaN =
HasIdentifier && IsInfOrNanFunction(FDecl->getName(), MathCheck::NaN);
if ((IsNaNOrIsUnordered || IsSpecialNaN) && FPO.getNoHonorNaNs()) {
Diag(Call->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled)
<< 1 << 0 << Call->getSourceRange();
else if ((IsStdFunction(FDecl, "isinf") ||
(IsStdFunction(FDecl, "isfinite") ||
(FDecl->getIdentifier() && FDecl->getName() == "infinity"))) &&
FPO.getNoHonorInfs())
Diag(Call->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled)
<< 0 << 0 << Call->getSourceRange();
} else {
bool IsInfOrIsFinite =
IsStdFunction(FDecl, "isinf") || IsStdFunction(FDecl, "isfinite");
bool IsInfinityOrIsSpecialInf =
HasIdentifier && ((FDecl->getName() == "infinity") ||
IsInfOrNanFunction(FDecl->getName(), MathCheck::Inf));
if ((IsInfOrIsFinite || IsInfinityOrIsSpecialInf) && FPO.getNoHonorInfs())
Diag(Call->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled)
<< 0 << 0 << Call->getSourceRange();
}
}

void Sema::CheckAbsoluteValueFunction(const CallExpr *Call,
Expand Down
6 changes: 4 additions & 2 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20148,8 +20148,10 @@ Sema::FunctionEmissionStatus Sema::getEmissionStatus(const FunctionDecl *FD,
// be emitted, because (say) the definition could include "inline".
const FunctionDecl *Def = FD->getDefinition();

return Def && !isDiscardableGVALinkage(
getASTContext().GetGVALinkageForFunction(Def));
// We can't compute linkage when we skip function bodies.
return Def && !Def->hasSkippedBody() &&
!isDiscardableGVALinkage(
getASTContext().GetGVALinkageForFunction(Def));
};

if (LangOpts.OpenMPIsTargetDevice) {
Expand Down
7 changes: 3 additions & 4 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12248,16 +12248,15 @@ Decl *Sema::ActOnUsingEnumDeclaration(Scope *S, AccessSpecifier AS,
SourceLocation EnumLoc, SourceRange TyLoc,
const IdentifierInfo &II, ParsedType Ty,
CXXScopeSpec *SS) {
assert(!SS->isInvalid() && "ScopeSpec is invalid");
assert(SS && !SS->isInvalid() && "ScopeSpec is invalid");
TypeSourceInfo *TSI = nullptr;
SourceLocation IdentLoc = TyLoc.getBegin();
QualType EnumTy = GetTypeFromParser(Ty, &TSI);
if (EnumTy.isNull()) {
Diag(IdentLoc, SS && isDependentScopeSpecifier(*SS)
Diag(IdentLoc, isDependentScopeSpecifier(*SS)
? diag::err_using_enum_is_dependent
: diag::err_unknown_typename)
<< II.getName()
<< SourceRange(SS ? SS->getBeginLoc() : IdentLoc, TyLoc.getEnd());
<< II.getName() << SourceRange(SS->getBeginLoc(), TyLoc.getEnd());
return nullptr;
}

Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3806,6 +3806,9 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
Overaligned, DeleteName);
}

if (OperatorDelete->isInvalidDecl())
return ExprError();

MarkFunctionReferenced(StartLoc, OperatorDelete);

// Check access and ambiguity of destructor if we're going to call it.
Expand Down
36 changes: 23 additions & 13 deletions clang/lib/Sema/SemaOverload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Casting.h"
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstdlib>
#include <optional>
Expand Down Expand Up @@ -9977,8 +9978,9 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
CandEnd = CandidateSet.end();
Cand != CandEnd; ++Cand)
if (Cand->Function) {
Fns.erase(Cand->Function);
if (FunctionTemplateDecl *FunTmpl = Cand->Function->getPrimaryTemplate())
FunctionDecl *Fn = Cand->Function;
Fns.erase(Fn);
if (FunctionTemplateDecl *FunTmpl = Fn->getPrimaryTemplate())
Fns.erase(FunTmpl);
}

Expand Down Expand Up @@ -11332,8 +11334,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
}
}

if (TakingCandidateAddress &&
!checkAddressOfCandidateIsAvailable(S, Cand->Function))
if (TakingCandidateAddress && !checkAddressOfCandidateIsAvailable(S, Fn))
return;

// Emit the generic diagnostic and, optionally, add the hints to it.
Expand All @@ -11359,6 +11360,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
/// over a candidate in any candidate set.
static bool CheckArityMismatch(Sema &S, OverloadCandidate *Cand,
unsigned NumArgs, bool IsAddressOf = false) {
assert(Cand->Function && "Candidate is required to be a function.");
FunctionDecl *Fn = Cand->Function;
unsigned MinParams = Fn->getMinRequiredExplicitArguments() +
((IsAddressOf && !Fn->isStatic()) ? 1 : 0);
Expand Down Expand Up @@ -11449,8 +11451,10 @@ static void DiagnoseArityMismatch(Sema &S, NamedDecl *Found, Decl *D,
/// Arity mismatch diagnosis specific to a function overload candidate.
static void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand,
unsigned NumFormalArgs) {
assert(Cand->Function && "Candidate must be a function");
FunctionDecl *Fn = Cand->Function;
if (!CheckArityMismatch(S, Cand, NumFormalArgs, Cand->TookAddressOfOverload))
DiagnoseArityMismatch(S, Cand->FoundDecl, Cand->Function, NumFormalArgs,
DiagnoseArityMismatch(S, Cand->FoundDecl, Fn, NumFormalArgs,
Cand->TookAddressOfOverload);
}

Expand Down Expand Up @@ -11750,19 +11754,22 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
static void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
unsigned NumArgs,
bool TakingCandidateAddress) {
assert(Cand->Function && "Candidate must be a function");
FunctionDecl *Fn = Cand->Function;
TemplateDeductionResult TDK = Cand->DeductionFailure.getResult();
if (TDK == TemplateDeductionResult::TooFewArguments ||
TDK == TemplateDeductionResult::TooManyArguments) {
if (CheckArityMismatch(S, Cand, NumArgs))
return;
}
DiagnoseBadDeduction(S, Cand->FoundDecl, Cand->Function, // pattern
DiagnoseBadDeduction(S, Cand->FoundDecl, Fn, // pattern
Cand->DeductionFailure, NumArgs, TakingCandidateAddress);
}

/// CUDA: diagnose an invalid call across targets.
static void DiagnoseBadTarget(Sema &S, OverloadCandidate *Cand) {
FunctionDecl *Caller = S.getCurFunctionDecl(/*AllowLambda=*/true);
assert(Cand->Function && "Candidate must be a Function.");
FunctionDecl *Callee = Cand->Function;

CUDAFunctionTarget CallerTarget = S.CUDA().IdentifyTarget(Caller),
Expand Down Expand Up @@ -11820,6 +11827,7 @@ static void DiagnoseBadTarget(Sema &S, OverloadCandidate *Cand) {
}

static void DiagnoseFailedEnableIfAttr(Sema &S, OverloadCandidate *Cand) {
assert(Cand->Function && "Candidate must be a function");
FunctionDecl *Callee = Cand->Function;
EnableIfAttr *Attr = static_cast<EnableIfAttr*>(Cand->DeductionFailure.Data);

Expand All @@ -11829,19 +11837,21 @@ static void DiagnoseFailedEnableIfAttr(Sema &S, OverloadCandidate *Cand) {
}

static void DiagnoseFailedExplicitSpec(Sema &S, OverloadCandidate *Cand) {
ExplicitSpecifier ES = ExplicitSpecifier::getFromDecl(Cand->Function);
assert(Cand->Function && "Candidate must be a function");
FunctionDecl *Fn = Cand->Function;
ExplicitSpecifier ES = ExplicitSpecifier::getFromDecl(Fn);
assert(ES.isExplicit() && "not an explicit candidate");

unsigned Kind;
switch (Cand->Function->getDeclKind()) {
switch (Fn->getDeclKind()) {
case Decl::Kind::CXXConstructor:
Kind = 0;
break;
case Decl::Kind::CXXConversion:
Kind = 1;
break;
case Decl::Kind::CXXDeductionGuide:
Kind = Cand->Function->isImplicit() ? 0 : 2;
Kind = Fn->isImplicit() ? 0 : 2;
break;
default:
llvm_unreachable("invalid Decl");
Expand All @@ -11851,7 +11861,7 @@ static void DiagnoseFailedExplicitSpec(Sema &S, OverloadCandidate *Cand) {
// (particularly an out-of-class definition) will typically lack the
// 'explicit' specifier.
// FIXME: This is probably a good thing to do for all 'candidate' notes.
FunctionDecl *First = Cand->Function->getFirstDecl();
FunctionDecl *First = Fn->getFirstDecl();
if (FunctionDecl *Pattern = First->getTemplateInstantiationPattern())
First = Pattern->getFirstDecl();

Expand Down Expand Up @@ -11920,6 +11930,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
unsigned NumArgs,
bool TakingCandidateAddress,
LangAS CtorDestAS = LangAS::Default) {
assert(Cand->Function && "Candidate must be a function");
FunctionDecl *Fn = Cand->Function;
if (shouldSkipNotingLambdaConversionDecl(Fn))
return;
Expand All @@ -11934,8 +11945,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
// Skip implicit member functions when trying to resolve
// the address of a an overload set for a function pointer.
if (Cand->TookAddressOfOverload &&
!Cand->Function->hasCXXExplicitFunctionObjectParameter() &&
!Cand->Function->isStatic())
!Fn->hasCXXExplicitFunctionObjectParameter() && !Fn->isStatic())
return;

// Note deleted candidates, but only if they're viable.
Expand Down Expand Up @@ -12033,7 +12043,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
return;

case ovl_fail_addr_not_available: {
bool Available = checkAddressOfCandidateIsAvailable(S, Cand->Function);
bool Available = checkAddressOfCandidateIsAvailable(S, Fn);
(void)Available;
assert(!Available);
break;
Expand Down
1 change: 0 additions & 1 deletion clang/lib/Sema/SemaX86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,6 @@ bool SemaX86::CheckBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
switch (BuiltinID) {
default:
return false;
case X86::BI__builtin_ia32_vec_ext_v2si:
case X86::BI__builtin_ia32_vec_ext_v2di:
case X86::BI__builtin_ia32_vextractf128_pd256:
case X86::BI__builtin_ia32_vextractf128_ps256:
Expand Down
19 changes: 19 additions & 0 deletions clang/lib/StaticAnalyzer/Core/CallEvent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -923,12 +923,31 @@ SVal AnyCXXConstructorCall::getCXXThisVal() const {
return UnknownVal();
}

static bool isWithinStdNamespace(const Decl *D) {
const DeclContext *DC = D->getDeclContext();
while (DC) {
if (const auto *NS = dyn_cast<NamespaceDecl>(DC);
NS && NS->isStdNamespace())
return true;
DC = DC->getParent();
}
return false;
}

void AnyCXXConstructorCall::getExtraInvalidatedValues(ValueList &Values,
RegionAndSymbolInvalidationTraits *ETraits) const {
SVal V = getCXXThisVal();
if (SymbolRef Sym = V.getAsSymbol(true))
ETraits->setTrait(Sym,
RegionAndSymbolInvalidationTraits::TK_SuppressEscape);

// Standard classes don't reinterpret-cast and modify super regions.
const bool IsStdClassCtor = isWithinStdNamespace(getDecl());
if (const MemRegion *Obj = V.getAsRegion(); Obj && IsStdClassCtor) {
ETraits->setTrait(
Obj, RegionAndSymbolInvalidationTraits::TK_DoNotInvalidateSuperRegion);
}

Values.push_back(V);
}

Expand Down
14 changes: 14 additions & 0 deletions clang/test/AST/Interp/builtin-constant-p.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=expected,both %s
// RUN: %clang_cc1 -verify=ref,both %s


static_assert(__builtin_constant_p(12), "");
static_assert(__builtin_constant_p(1.0), "");

constexpr int I = 100;
static_assert(__builtin_constant_p(I), "");
static_assert(__builtin_constant_p(I + 10), "");
static_assert(__builtin_constant_p(I + 10.0), "");
static_assert(__builtin_constant_p(nullptr), "");
static_assert(__builtin_constant_p(&I), ""); // both-error {{failed due to requirement}}
static_assert(__builtin_constant_p((void)I), ""); // both-error {{failed due to requirement}}
4 changes: 4 additions & 0 deletions clang/test/AST/Interp/records.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1551,8 +1551,12 @@ namespace ArrayInitChain {

constexpr CustomOperandVal A[] = {
{},
{{"depctr_hold_cnt"}, 12, 13},
};
static_assert(A[0].Str.S == nullptr, "");
static_assert(A[0].Width == 0, "");
static_assert(A[0].Mask == 1, "");

static_assert(A[1].Width == 12, "");
static_assert(A[1].Mask == 13, "");
}
115 changes: 115 additions & 0 deletions clang/test/Analysis/call-invalidation.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify -analyzer-config eagerly-assume=false %s

template <class T> void clang_analyzer_dump(T);
void clang_analyzer_eval(bool);

void usePointer(int * const *);
Expand Down Expand Up @@ -165,3 +166,117 @@ void testMixedConstNonConstCalls() {
useFirstNonConstSecondConst(&(s2.x), &(s2.y));
clang_analyzer_eval(s2.y == 1); // expected-warning{{UNKNOWN}}
}

namespace std {
class Opaque {
public:
Opaque();
int nested_member;
};
} // namespace std

struct StdWrappingOpaque {
std::Opaque o; // first member
int uninit;
};
struct StdWrappingOpaqueSwapped {
int uninit; // first member
std::Opaque o;
};

int testStdCtorDoesNotInvalidateParentObject() {
StdWrappingOpaque obj;
int x = obj.o.nested_member; // no-garbage: std::Opaque::ctor might initialized this
int y = obj.uninit; // FIXME: We should have a garbage read here. Read the details.
// As the first member ("obj.o") is invalidated, a conjured default binding is bound
// to the offset 0 within cluster "obj", and this masks every uninitialized fields
// that follows. We need a better store with extents to fix this.
return x + y;
}

int testStdCtorDoesNotInvalidateParentObjectSwapped() {
StdWrappingOpaqueSwapped obj;
int x = obj.o.nested_member; // no-garbage: std::Opaque::ctor might initialized this
int y = obj.uninit; // expected-warning {{Assigned value is garbage or undefined}}
return x + y;
}

class UserProvidedOpaque {
public:
UserProvidedOpaque(); // might reinterpret_cast(this)
int nested_member;
};

struct WrappingUserProvidedOpaque {
UserProvidedOpaque o; // first member
int uninit;
};
struct WrappingUserProvidedOpaqueSwapped {
int uninit; // first member
UserProvidedOpaque o;
};

int testUserProvidedCtorInvalidatesParentObject() {
WrappingUserProvidedOpaque obj;
int x = obj.o.nested_member; // no-garbage: UserProvidedOpaque::ctor might initialized this
int y = obj.uninit; // no-garbage: UserProvidedOpaque::ctor might reinterpret_cast(this) and write to the "uninit" member.
return x + y;
}

int testUserProvidedCtorInvalidatesParentObjectSwapped() {
WrappingUserProvidedOpaqueSwapped obj;
int x = obj.o.nested_member; // no-garbage: same as above
int y = obj.uninit; // no-garbage: same as above
return x + y;
}

struct WrappingStdWrappingOpaqueOuterInits {
int first = 1;
std::Opaque second;
int third = 3;
WrappingStdWrappingOpaqueOuterInits() {
clang_analyzer_dump(first); // expected-warning {{1 S32b}}
clang_analyzer_dump(second.nested_member); // expected-warning {{derived_}}
clang_analyzer_dump(third); // expected-warning {{3 S32b}}
}
};

struct WrappingUserProvidedOpaqueOuterInits {
int first = 1; // Potentially overwritten by UserProvidedOpaque::ctor
UserProvidedOpaque second; // Invalidates the object so far.
int third = 3; // Happens after UserProvidedOpaque::ctor, thus preserved!
WrappingUserProvidedOpaqueOuterInits() {
clang_analyzer_dump(first); // expected-warning {{derived_}}
clang_analyzer_dump(second.nested_member); // expected-warning {{derived_}}
clang_analyzer_dump(third); // expected-warning {{3 S32b}}
}
};

extern "C++" {
namespace std {
inline namespace v1 {
namespace custom_ranges {
struct Fancy {
struct iterator {
struct Opaque {
Opaque();
int nested_member;
}; // struct Opaque
}; // struct iterator
}; // struct Fancy
} // namespace custom_ranges
} // namespace v1
} // namespace std
} // extern "C++"

struct StdWrappingFancyOpaque {
int uninit;
std::custom_ranges::Fancy::iterator::Opaque o;
};

int testNestedStdNamespacesAndRecords() {
StdWrappingFancyOpaque obj;
int x = obj.o.nested_member; // no-garbage: ctor
int y = obj.uninit; // expected-warning {{Assigned value is garbage or undefined}}
return x + y;
}
12 changes: 1 addition & 11 deletions clang/test/Analysis/ctor-array.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-disable-checker=cplusplus -analyzer-config c++-inlining=constructors -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config c++-inlining=constructors -verify %s

#include "Inputs/system-header-simulator-cxx.h"

Expand Down Expand Up @@ -119,16 +119,6 @@ struct s5 {
};

void g1(void) {
// FIXME: This test requires -analyzer-disable-checker=cplusplus,
// because of the checker's weird behaviour in case of arrays.
// E.g.:
// s3 *arr = new s3[4];
// s3 *arr2 = new (arr + 1) s3[1];
// ^~~~~~~~~~~~~~~~~~~
// warning: 12 bytes is possibly not enough
// for array allocation which requires
// 4 bytes.

s5::c = 0;
s5 *arr = new s5[4];
new (arr + 1) s5[3];
Expand Down
2 changes: 0 additions & 2 deletions clang/test/Analysis/ctor.mm
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,6 @@ void testNonPODCopyConstructor() {
namespace ConstructorVirtualCalls {
class A {
public:
int *out1, *out2, *out3;

virtual int get() { return 1; }

A(int *out1) {
Expand Down
Loading