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;
}
1 change: 1 addition & 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 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
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
18 changes: 18 additions & 0 deletions clang/lib/AST/Interp/Compiler.cpp
Original file line number Diff line number Diff line change
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 @@ -4698,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 @@ -5239,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
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
7 changes: 4 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 @@ -2026,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
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
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}}
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
42 changes: 25 additions & 17 deletions clang/test/CodeGen/aix-builtin-cpu-is.c
Original file line number Diff line number Diff line change
@@ -1,52 +1,60 @@
// RUN: echo "int main() { return __builtin_cpu_is(\"ppc970\");}" > %t.c
// RUN: echo "int main() { return __builtin_cpu_is(\"ppc970\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s

// RUN: echo "int main() { return __builtin_cpu_is(\"ppc-cell-be\");}" > %t.c
// RUN: echo "int main() { return __builtin_cpu_is(\"ppc-cell-be\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s

// RUN: echo "int main() { return __builtin_cpu_is(\"ppca2\");}" > %t.c
// RUN: echo "int main() { return __builtin_cpu_is(\"ppca2\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s

// RUN: echo "int main() { return __builtin_cpu_is(\"ppc405\");}" > %t.c
// RUN: echo "int main() { return __builtin_cpu_is(\"ppc405\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s

// RUN: echo "int main() { return __builtin_cpu_is(\"ppc440\");}" > %t.c
// RUN: echo "int main() { return __builtin_cpu_is(\"ppc440\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s

// RUN: echo "int main() { return __builtin_cpu_is(\"ppc464\");}" > %t.c
// RUN: echo "int main() { return __builtin_cpu_is(\"ppc464\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s

// RUN: echo "int main() { return __builtin_cpu_is(\"ppc476\");}" > %t.c
// RUN: echo "int main() { return __builtin_cpu_is(\"ppc476\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s

// RUN: echo "int main() { return __builtin_cpu_is(\"power4\");}" > %t.c
// RUN: echo "int main() { return __builtin_cpu_is(\"power4\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s

// RUN: echo "int main() { return __builtin_cpu_is(\"power5\");}" > %t.c
// RUN: echo "int main() { return __builtin_cpu_is(\"power5\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s

// RUN: echo "int main() { return __builtin_cpu_is(\"power5+\");}" > %t.c
// RUN: echo "int main() { return __builtin_cpu_is(\"power5+\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s

// RUN: echo "int main() { return __builtin_cpu_is(\"power6\");}" > %t.c
// RUN: echo "int main() { return __builtin_cpu_is(\"power6\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s

// RUN: echo "int main() { return __builtin_cpu_is(\"power6x\");}" > %t.c
// RUN: echo "int main() { return __builtin_cpu_is(\"power6x\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s

// RUN: echo "int main() { return __builtin_cpu_is(\"power7\");}" > %t.c
// RUN: echo "int main() { return __builtin_cpu_is(\"power7\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s -DVALUE=32768 \
// RUN: --check-prefix=CHECKOP

// RUN: echo "int main() { return __builtin_cpu_is(\"power8\");}" > %t.c
// RUN: echo "int main() { return __builtin_cpu_is(\"pwr7\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s -DVALUE=32768 \
// RUN: --check-prefix=CHECKOP

// RUN: echo "int main() { return __builtin_cpu_is(\"power8\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s -DVALUE=65536 \
// RUN: --check-prefix=CHECKOP

// RUN: echo "int main() { return __builtin_cpu_is(\"power9\");}" > %t.c
// RUN: echo "int main() { return __builtin_cpu_is(\"power9\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s -DVALUE=131072\
// RUN: --check-prefix=CHECKOP

// RUN: echo "int main() { return __builtin_cpu_is(\"power10\");}" > %t.c
// RUN: echo "int main() { return __builtin_cpu_is(\"power10\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s -DVALUE=262144 \
// RUN: --check-prefix=CHECKOP

// RUN: echo "int main() { return __builtin_cpu_is(\"pwr10\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s -DVALUE=262144 \
// RUN: --check-prefix=CHECKOP

Expand All @@ -67,7 +75,7 @@
// CHECKOP-NEXT: %retval = alloca i32, align 4
// CHECKOP-NEXT: store i32 0, ptr %retval, align 4
// CHECKOP-NEXT: %0 = load i32, ptr getelementptr inbounds ({ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i64, i32, i32, i32, i32, i64, i64, i64, i64, i32, i32, i32, i32, i32, i32, i64, i32, i8, i8, i8, i8, i32, i32, i16, i16, [3 x i32], i32 }, ptr @_system_configuration, i32 0, i32 1), align 4
// CHECKOP-NEXT: %1 = icmp eq i32 %0, [[VALUE]]
// CHECKOP-NEXT: %1 = icmp eq i32 %0, [[VALUE]]
// CHECKOP-NEXT: %conv = zext i1 %1 to i32
// CHECKOP-NEXT: ret i32 %conv
// CHECKOP-NEXT: }
Expand Down
110 changes: 68 additions & 42 deletions clang/test/CodeGen/builtin-cpu-supports.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,60 +143,82 @@ int v4() { return __builtin_cpu_supports("x86-64-v4"); }
// CHECK-PPC-NEXT: br label [[RETURN]]
// CHECK-PPC: if.else5:
// CHECK-PPC-NEXT: [[CPU_IS6:%.*]] = call i32 @llvm.ppc.fixed.addr.ld(i32 3)
// CHECK-PPC-NEXT: [[TMP9:%.*]] = icmp eq i32 [[CPU_IS6]], 45
// CHECK-PPC-NEXT: br i1 [[TMP9]], label [[IF_THEN7:%.*]], label [[IF_ELSE9:%.*]]
// CHECK-PPC-NEXT: [[TMP9:%.*]] = icmp eq i32 [[CPU_IS6]], 39
// CHECK-PPC-NEXT: br i1 [[TMP9]], label [[IF_THEN7:%.*]], label [[IF_ELSE8:%.*]]
// CHECK-PPC: if.then7:
// CHECK-PPC-NEXT: [[TMP10:%.*]] = load i32, ptr [[A_ADDR]], align 4
// CHECK-PPC-NEXT: [[ADD8:%.*]] = add nsw i32 [[TMP10]], 3
// CHECK-PPC-NEXT: store i32 [[ADD8]], ptr [[RETVAL]], align 4
// CHECK-PPC-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP10]], 3
// CHECK-PPC-NEXT: store i32 [[MUL]], ptr [[RETVAL]], align 4
// CHECK-PPC-NEXT: br label [[RETURN]]
// CHECK-PPC: if.else9:
// CHECK-PPC-NEXT: [[CPU_IS10:%.*]] = call i32 @llvm.ppc.fixed.addr.ld(i32 3)
// CHECK-PPC-NEXT: [[TMP11:%.*]] = icmp eq i32 [[CPU_IS10]], 46
// CHECK-PPC-NEXT: br i1 [[TMP11]], label [[IF_THEN11:%.*]], label [[IF_ELSE13:%.*]]
// CHECK-PPC: if.then11:
// CHECK-PPC: if.else8:
// CHECK-PPC-NEXT: [[CPU_IS9:%.*]] = call i32 @llvm.ppc.fixed.addr.ld(i32 3)
// CHECK-PPC-NEXT: [[TMP11:%.*]] = icmp eq i32 [[CPU_IS9]], 33
// CHECK-PPC-NEXT: br i1 [[TMP11]], label [[IF_THEN10:%.*]], label [[IF_ELSE12:%.*]]
// CHECK-PPC: if.then10:
// CHECK-PPC-NEXT: [[TMP12:%.*]] = load i32, ptr [[A_ADDR]], align 4
// CHECK-PPC-NEXT: [[SUB12:%.*]] = sub nsw i32 [[TMP12]], 3
// CHECK-PPC-NEXT: store i32 [[SUB12]], ptr [[RETVAL]], align 4
// CHECK-PPC-NEXT: [[MUL11:%.*]] = mul nsw i32 [[TMP12]], 4
// CHECK-PPC-NEXT: store i32 [[MUL11]], ptr [[RETVAL]], align 4
// CHECK-PPC-NEXT: br label [[RETURN]]
// CHECK-PPC: if.else13:
// CHECK-PPC-NEXT: [[CPU_IS14:%.*]] = call i32 @llvm.ppc.fixed.addr.ld(i32 3)
// CHECK-PPC-NEXT: [[TMP13:%.*]] = icmp eq i32 [[CPU_IS14]], 47
// CHECK-PPC-NEXT: br i1 [[TMP13]], label [[IF_THEN15:%.*]], label [[IF_ELSE17:%.*]]
// CHECK-PPC: if.then15:
// CHECK-PPC: if.else12:
// CHECK-PPC-NEXT: [[CPU_IS13:%.*]] = call i32 @llvm.ppc.fixed.addr.ld(i32 3)
// CHECK-PPC-NEXT: [[TMP13:%.*]] = icmp eq i32 [[CPU_IS13]], 45
// CHECK-PPC-NEXT: br i1 [[TMP13]], label [[IF_THEN14:%.*]], label [[IF_ELSE16:%.*]]
// CHECK-PPC: if.then14:
// CHECK-PPC-NEXT: [[TMP14:%.*]] = load i32, ptr [[A_ADDR]], align 4
// CHECK-PPC-NEXT: [[ADD16:%.*]] = add nsw i32 [[TMP14]], 7
// CHECK-PPC-NEXT: store i32 [[ADD16]], ptr [[RETVAL]], align 4
// CHECK-PPC-NEXT: [[ADD15:%.*]] = add nsw i32 [[TMP14]], 3
// CHECK-PPC-NEXT: store i32 [[ADD15]], ptr [[RETVAL]], align 4
// CHECK-PPC-NEXT: br label [[RETURN]]
// CHECK-PPC: if.else17:
// CHECK-PPC-NEXT: [[CPU_IS18:%.*]] = call i32 @llvm.ppc.fixed.addr.ld(i32 3)
// CHECK-PPC-NEXT: [[TMP15:%.*]] = icmp eq i32 [[CPU_IS18]], 48
// CHECK-PPC-NEXT: br i1 [[TMP15]], label [[IF_THEN19:%.*]], label [[IF_END:%.*]]
// CHECK-PPC: if.then19:
// CHECK-PPC: if.else16:
// CHECK-PPC-NEXT: [[CPU_IS17:%.*]] = call i32 @llvm.ppc.fixed.addr.ld(i32 3)
// CHECK-PPC-NEXT: [[TMP15:%.*]] = icmp eq i32 [[CPU_IS17]], 46
// CHECK-PPC-NEXT: br i1 [[TMP15]], label [[IF_THEN18:%.*]], label [[IF_ELSE20:%.*]]
// CHECK-PPC: if.then18:
// CHECK-PPC-NEXT: [[TMP16:%.*]] = load i32, ptr [[A_ADDR]], align 4
// CHECK-PPC-NEXT: [[SUB20:%.*]] = sub nsw i32 [[TMP16]], 7
// CHECK-PPC-NEXT: store i32 [[SUB20]], ptr [[RETVAL]], align 4
// CHECK-PPC-NEXT: [[SUB19:%.*]] = sub nsw i32 [[TMP16]], 3
// CHECK-PPC-NEXT: store i32 [[SUB19]], ptr [[RETVAL]], align 4
// CHECK-PPC-NEXT: br label [[RETURN]]
// CHECK-PPC: if.else20:
// CHECK-PPC-NEXT: [[CPU_IS21:%.*]] = call i32 @llvm.ppc.fixed.addr.ld(i32 3)
// CHECK-PPC-NEXT: [[TMP17:%.*]] = icmp eq i32 [[CPU_IS21]], 47
// CHECK-PPC-NEXT: br i1 [[TMP17]], label [[IF_THEN22:%.*]], label [[IF_ELSE24:%.*]]
// CHECK-PPC: if.then22:
// CHECK-PPC-NEXT: [[TMP18:%.*]] = load i32, ptr [[A_ADDR]], align 4
// CHECK-PPC-NEXT: [[ADD23:%.*]] = add nsw i32 [[TMP18]], 7
// CHECK-PPC-NEXT: store i32 [[ADD23]], ptr [[RETVAL]], align 4
// CHECK-PPC-NEXT: br label [[RETURN]]
// CHECK-PPC: if.else24:
// CHECK-PPC-NEXT: [[CPU_IS25:%.*]] = call i32 @llvm.ppc.fixed.addr.ld(i32 3)
// CHECK-PPC-NEXT: [[TMP19:%.*]] = icmp eq i32 [[CPU_IS25]], 48
// CHECK-PPC-NEXT: br i1 [[TMP19]], label [[IF_THEN26:%.*]], label [[IF_END:%.*]]
// CHECK-PPC: if.then26:
// CHECK-PPC-NEXT: [[TMP20:%.*]] = load i32, ptr [[A_ADDR]], align 4
// CHECK-PPC-NEXT: [[SUB27:%.*]] = sub nsw i32 [[TMP20]], 7
// CHECK-PPC-NEXT: store i32 [[SUB27]], ptr [[RETVAL]], align 4
// CHECK-PPC-NEXT: br label [[RETURN]]
// CHECK-PPC: if.end:
// CHECK-PPC-NEXT: br label [[IF_END21:%.*]]
// CHECK-PPC: if.end21:
// CHECK-PPC-NEXT: br label [[IF_END22:%.*]]
// CHECK-PPC: if.end22:
// CHECK-PPC-NEXT: br label [[IF_END23:%.*]]
// CHECK-PPC: if.end23:
// CHECK-PPC-NEXT: br label [[IF_END24:%.*]]
// CHECK-PPC: if.end24:
// CHECK-PPC-NEXT: br label [[IF_END25:%.*]]
// CHECK-PPC: if.end25:
// CHECK-PPC-NEXT: br label [[IF_END26:%.*]]
// CHECK-PPC: if.end26:
// CHECK-PPC-NEXT: [[TMP17:%.*]] = load i32, ptr [[A_ADDR]], align 4
// CHECK-PPC-NEXT: [[ADD27:%.*]] = add nsw i32 [[TMP17]], 5
// CHECK-PPC-NEXT: store i32 [[ADD27]], ptr [[RETVAL]], align 4
// CHECK-PPC-NEXT: br label [[IF_END28:%.*]]
// CHECK-PPC: if.end28:
// CHECK-PPC-NEXT: br label [[IF_END29:%.*]]
// CHECK-PPC: if.end29:
// CHECK-PPC-NEXT: br label [[IF_END30:%.*]]
// CHECK-PPC: if.end30:
// CHECK-PPC-NEXT: br label [[IF_END31:%.*]]
// CHECK-PPC: if.end31:
// CHECK-PPC-NEXT: br label [[IF_END32:%.*]]
// CHECK-PPC: if.end32:
// CHECK-PPC-NEXT: br label [[IF_END33:%.*]]
// CHECK-PPC: if.end33:
// CHECK-PPC-NEXT: br label [[IF_END34:%.*]]
// CHECK-PPC: if.end34:
// CHECK-PPC-NEXT: br label [[IF_END35:%.*]]
// CHECK-PPC: if.end35:
// CHECK-PPC-NEXT: [[TMP21:%.*]] = load i32, ptr [[A_ADDR]], align 4
// CHECK-PPC-NEXT: [[ADD36:%.*]] = add nsw i32 [[TMP21]], 5
// CHECK-PPC-NEXT: store i32 [[ADD36]], ptr [[RETVAL]], align 4
// CHECK-PPC-NEXT: br label [[RETURN]]
// CHECK-PPC: return:
// CHECK-PPC-NEXT: [[TMP18:%.*]] = load i32, ptr [[RETVAL]], align 4
// CHECK-PPC-NEXT: ret i32 [[TMP18]]
// CHECK-PPC-NEXT: [[TMP22:%.*]] = load i32, ptr [[RETVAL]], align 4
// CHECK-PPC-NEXT: ret i32 [[TMP22]]
//
int test_ppc(int a) {
if (__builtin_cpu_supports("arch_3_00")) // HWCAP2
Expand All @@ -205,6 +227,10 @@ int test_ppc(int a) {
return a - 5;
else if (__builtin_cpu_is("power7")) // CPUID
return a + a;
else if (__builtin_cpu_is("pwr7")) // CPUID
return a * 3;
else if (__builtin_cpu_is("ppc970")) // CPUID
return a * 4;
else if (__builtin_cpu_is("power8"))
return a + 3;
else if (__builtin_cpu_is("power9"))
Expand Down
8 changes: 8 additions & 0 deletions clang/test/Driver/cuda-cross-compiling.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,11 @@
// RUN: | FileCheck -check-prefix=GENERIC %s

// GENERIC-NOT: -cc1" "-triple" "nvptx64-nvidia-cuda" {{.*}} "-target-cpu"

//
// Test forwarding the necessary +ptx feature.
//
// RUN: %clang -target nvptx64-nvidia-cuda --cuda-feature=+ptx63 -march=sm_52 -### %s 2>&1 \
// RUN: | FileCheck -check-prefix=FEATURE %s

// FEATURE: clang-nvlink-wrapper{{.*}}"--feature" "+ptx63"
5 changes: 4 additions & 1 deletion clang/test/Driver/lto-jobs.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@
// RUN: %clang --target=x86_64-sie-ps5 -### %s -flto=thin -flto-jobs=5 2> %t
// RUN: FileCheck -check-prefix=CHECK-LINK-THIN-JOBS-ACTION < %t %s
//
// RUN: %clang --target=x86_64-sie-ps5 -### %s -flto-jobs=5 2> %t
// RUN: FileCheck -check-prefix=CHECK-LINK-THIN-JOBS-ACTION < %t %s
//
// CHECK-LINK-THIN-JOBS-ACTION: "-plugin-opt=jobs=5"
//
// RUN: %clang --target=x86_64-scei-ps4 -### %s -flto=thin -flto-jobs=5 2> %t
// RUN: FileCheck -check-prefix=CHECK-PS4-LINK-THIN-JOBS-ACTION < %t %s
//
// CHECK-PS4-LINK-THIN-JOBS-ACTION: "-lto-thin-debug-options= -threads=5"
// CHECK-PS4-LINK-THIN-JOBS-ACTION: "-lto-debug-options= -threads=5"

// RUN: %clang --target=x86_64-apple-darwin13.3.0 -### %s -flto=thin -flto-jobs=5 2> %t
// RUN: FileCheck -check-prefix=CHECK-LINK-THIN-JOBS2-ACTION < %t %s
Expand Down
18 changes: 8 additions & 10 deletions clang/test/Driver/ps4-linker.c
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
// Test the driver's control over the JustMyCode behavior with linker flags.

// RUN: %clang --target=x86_64-scei-ps4 -fjmc %s -### 2>&1 | FileCheck --check-prefixes=CHECK,CHECK-LIB %s
// RUN: %clang --target=x86_64-scei-ps4 -flto=thin -fjmc %s -### 2>&1 | FileCheck --check-prefixes=CHECK-THIN-LTO,CHECK-LIB %s
// RUN: %clang --target=x86_64-scei-ps4 -flto=full -fjmc %s -### 2>&1 | FileCheck --check-prefixes=CHECK-FULL-LTO,CHECK-LIB %s
// RUN: %clang --target=x86_64-scei-ps4 -fjmc %s -### 2>&1 | FileCheck --check-prefixes=CHECK-LTO,CHECK-LIB %s
// RUN: %clang --target=x86_64-scei-ps4 -flto=thin -fjmc %s -### 2>&1 | FileCheck --check-prefixes=CHECK-LTO,CHECK-LIB %s
// RUN: %clang --target=x86_64-scei-ps4 -flto=full -fjmc %s -### 2>&1 | FileCheck --check-prefixes=CHECK-LTO,CHECK-LIB %s

// CHECK-NOT: -enable-jmc-instrument
// CHECK-THIN-LTO: "-lto-thin-debug-options= -enable-jmc-instrument"
// CHECK-FULL-LTO: "-lto-debug-options= -enable-jmc-instrument"
// CHECK-LTO: "-lto-debug-options= -enable-jmc-instrument"

// Check the default library name.
// CHECK-LIB: "--whole-archive" "-lSceDbgJmc" "--no-whole-archive"

// Test the driver's control over the -fcrash-diagnostics-dir behavior with linker flags.

// RUN: %clang --target=x86_64-scei-ps4 -flto=thin -fcrash-diagnostics-dir=mydumps %s -### 2>&1 | FileCheck --check-prefixes=CHECK-DIAG-THIN-LTO %s
// RUN: %clang --target=x86_64-scei-ps4 -flto=full -fcrash-diagnostics-dir=mydumps %s -### 2>&1 | FileCheck --check-prefixes=CHECK-DIAG-FULL-LTO %s
// RUN: %clang --target=x86_64-scei-ps4 -fcrash-diagnostics-dir=mydumps %s -### 2>&1 | FileCheck --check-prefixes=CHECK-DIAG-LTO %s
// RUN: %clang --target=x86_64-scei-ps4 -flto=thin -fcrash-diagnostics-dir=mydumps %s -### 2>&1 | FileCheck --check-prefixes=CHECK-DIAG-LTO %s
// RUN: %clang --target=x86_64-scei-ps4 -flto=full -fcrash-diagnostics-dir=mydumps %s -### 2>&1 | FileCheck --check-prefixes=CHECK-DIAG-LTO %s

// CHECK-DIAG-THIN-LTO: "-lto-thin-debug-options= -crash-diagnostics-dir=mydumps"
// CHECK-DIAG-FULL-LTO: "-lto-debug-options= -crash-diagnostics-dir=mydumps"
// CHECK-DIAG-LTO: "-lto-debug-options= -crash-diagnostics-dir=mydumps"
10 changes: 4 additions & 6 deletions clang/test/Driver/ps5-linker.c
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
// Test the driver's control over the JustMyCode behavior with linker flags.

// RUN: %clang --target=x86_64-scei-ps5 -fjmc %s -### 2>&1 | FileCheck --check-prefixes=CHECK,CHECK-LIB %s
// RUN: %clang --target=x86_64-scei-ps5 -flto -fjmc %s -### 2>&1 | FileCheck --check-prefixes=CHECK-LTO,CHECK-LIB %s
// RUN: %clang --target=x86_64-scei-ps5 -flto -fjmc %s -### 2>&1 | FileCheck --check-prefixes=CHECK,CHECK-LIB %s

// CHECK-NOT: -plugin-opt=-enable-jmc-instrument
// CHECK-LTO: -plugin-opt=-enable-jmc-instrument
// CHECK: -plugin-opt=-enable-jmc-instrument

// Check the default library name.
// CHECK-LIB: "--whole-archive" "-lSceJmc_nosubmission" "--no-whole-archive"

// Test the driver's control over the -fcrash-diagnostics-dir behavior with linker flags.

// RUN: %clang --target=x86_64-scei-ps5 -fcrash-diagnostics-dir=mydumps %s -### 2>&1 | FileCheck --check-prefixes=CHECK-DIAG %s
// RUN: %clang --target=x86_64-scei-ps5 -flto -fcrash-diagnostics-dir=mydumps %s -### 2>&1 | FileCheck --check-prefixes=CHECK-DIAG-LTO %s
// RUN: %clang --target=x86_64-scei-ps5 -flto -fcrash-diagnostics-dir=mydumps %s -### 2>&1 | FileCheck --check-prefixes=CHECK-DIAG %s

// CHECK-DIAG-NOT: -plugin-opt=-crash-diagnostics-dir=mydumps
// CHECK-DIAG-LTO: -plugin-opt=-crash-diagnostics-dir=mydumps
// CHECK-DIAG: -plugin-opt=-crash-diagnostics-dir=mydumps
23 changes: 22 additions & 1 deletion clang/test/Driver/unified-lto.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,27 @@
// NOUNIT-NOT: "-flto-unit"

// RUN: %clang --target=x86_64-sie-ps5 -### %s -funified-lto 2>&1 | FileCheck --check-prefix=NOUNILTO %s
// NOUNILTO: clang: warning: argument unused during compilation: '-funified-lto'
// NOUNILTO: "-cc1"
// NOUNILTO-NOT: "-funified-lto

// On PlayStation -funified-lto is the default. `-flto(=...)` influences the
// `--lto=...` option passed to linker, unless `-fno-unified-lto` is supplied.
// PS4:
// RUN: %clang --target=x86_64-sie-ps4 -### %s 2>&1 | FileCheck --check-prefixes=LD,LTOFULL %s
// RUN: %clang --target=x86_64-sie-ps4 -### %s -flto 2>&1 | FileCheck --check-prefixes=LD,LTOFULL %s
// RUN: %clang --target=x86_64-sie-ps4 -### %s -flto=full 2>&1 | FileCheck --check-prefixes=LD,LTOFULL %s
// RUN: %clang --target=x86_64-sie-ps4 -### %s -flto=thin 2>&1 | FileCheck --check-prefixes=LD,LTOTHIN %s
// RUN: %clang --target=x86_64-sie-ps4 -### %s -fno-unified-lto -flto=full 2>&1 | FileCheck --check-prefixes=LD,NOLTO %s
// RUN: %clang --target=x86_64-sie-ps4 -### %s -fno-unified-lto -flto=thin 2>&1 | FileCheck --check-prefixes=LD,NOLTO %s
// PS5:
// RUN: %clang --target=x86_64-sie-ps5 -### %s 2>&1 | FileCheck --check-prefixes=LD,LTOFULL %s
// RUN: %clang --target=x86_64-sie-ps5 -### %s -flto 2>&1 | FileCheck --check-prefixes=LD,LTOFULL %s
// RUN: %clang --target=x86_64-sie-ps5 -### %s -flto=full 2>&1 | FileCheck --check-prefixes=LD,LTOFULL %s
// RUN: %clang --target=x86_64-sie-ps5 -### %s -flto=thin 2>&1 | FileCheck --check-prefixes=LD,LTOTHIN %s
// RUN: %clang --target=x86_64-sie-ps5 -### %s -fno-unified-lto -flto=full 2>&1 | FileCheck --check-prefixes=LD,NOLTO %s
// RUN: %clang --target=x86_64-sie-ps5 -### %s -fno-unified-lto -flto=thin 2>&1 | FileCheck --check-prefixes=LD,NOLTO %s

// LD: {{.*ld}}"
// LTOFULL-SAME: "--lto=full"
// LTOTHIN-SAME: "--lto=thin"
// NOLTO-NOT: "--lto
13 changes: 13 additions & 0 deletions clang/test/Frontend/skip-function-bodies.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Trivial check to ensure skip-function-bodies flag is propagated.
//
// RUN: %clang_cc1 -verify -skip-function-bodies -pedantic-errors %s
// expected-no-diagnostics

int f() {
// normally this should emit some diags, but we're skipping it!
this is garbage;
}

// Make sure we only accept it as a cc1 arg.
// RUN: not %clang -skip-function-bodies %s 2>&1 | FileCheck %s
// CHECK: clang: error: unknown argument '-skip-function-bodies'; did you mean '-Xclang -skip-function-bodies'?
5 changes: 3 additions & 2 deletions clang/test/Headers/float.c
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,9 @@
#ifndef NAN
#error "Mandatory macro NAN is missing."
#endif
// FIXME: the NAN diagnostic should only be issued once, not twice.
_Static_assert(_Generic(INFINITY, float : 1, default : 0), ""); // finite-warning {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}}
// FIXME: the NAN and INF diagnostics should only be issued once, not twice.
_Static_assert(_Generic(INFINITY, float : 1, default : 0), ""); // finite-warning {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} \
finite-warning {{use of infinity is undefined behavior due to the currently enabled floating-point options}}
_Static_assert(_Generic(NAN, float : 1, default : 0), ""); // finite-warning {{use of NaN is undefined behavior due to the currently enabled floating-point options}} \
finite-warning {{use of NaN via a macro is undefined behavior due to the currently enabled floating-point options}}

Expand Down
2 changes: 1 addition & 1 deletion clang/test/Misc/target-invalid-cpu-note.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@

// RUN: not %clang_cc1 -triple powerpc--- -target-cpu not-a-cpu -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix PPC
// PPC: error: unknown target CPU 'not-a-cpu'
// PPC-NEXT: note: valid target CPU values are: 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{{$}}
// PPC-NEXT: note: valid target CPU values are: generic, 440, 440fp, ppc440, 450, 601, 602, 603, 603e, 603ev, 604, 604e, 620, 630, g3, 7400, g4, 7450, g4+, 750, 8548, ppc405, ppc464, ppc476, 970, ppc970, g5, a2, ppca2, ppc-cell-be, e500, e500mc, e5500, power3, pwr3, pwr4, power4, pwr5, power5, pwr5+, power5+, pwr5x, power5x, pwr6, power6, pwr6x, power6x, pwr7, power7, pwr8, power8, pwr9, power9, pwr10, power10, pwr11, power11, powerpc, ppc, ppc32, powerpc64, ppc64, powerpc64le, ppc64le, future{{$}}

// RUN: not %clang_cc1 -triple mips--- -target-cpu not-a-cpu -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix MIPS
// MIPS: error: unknown target CPU 'not-a-cpu'
Expand Down
14 changes: 14 additions & 0 deletions clang/test/Sema/builtin-cpu-supports.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
// RUN: %clang_cc1 -fsyntax-only -triple aarch64-linux-gnu -verify %s
// RUN: %clang_cc1 -fsyntax-only -triple riscv32-linux-gnu -verify %s
// RUN: %clang_cc1 -fsyntax-only -triple riscv64-linux-gnu -verify %s
// RUN: %clang_cc1 -fsyntax-only -triple powerpc64le-unknown-linux -verify %s
// RUN: %clang_cc1 -fsyntax-only -triple powerpc64-unknown-aix7.2.0.0 -verify %s
// RUN: %clang_cc1 -fsyntax-only -triple powerpc-unknown-aix7.2.0.0 -verify %s

extern void a(const char *);

Expand Down Expand Up @@ -45,5 +48,16 @@ int main(void) {
a("vsx");
#endif

#ifdef __powerpc__
if (__builtin_cpu_is("garbage")) // expected-error {{invalid cpu name for builtin}}
a("vsx");

if (__builtin_cpu_is("power3")) // expected-error {{invalid cpu name for builtin}}
a("vsx");

if (__builtin_cpu_supports("garbage")) // expected-warning {{invalid cpu feature string for builtin}}
a("vsx");
#endif

return 0;
}
28 changes: 20 additions & 8 deletions clang/test/Sema/warn-infinity-nan-disabled-lnx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,15 @@ class numeric_limits<double> {

int compareit(float a, float b) {
volatile int i, j, k, l, m, n, o, p;
// no-inf-no-nan-warning@+2 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}}
// no-inf-no-nan-warning@+4 {{use of infinity is undefined behavior due to the currently enabled floating-point options}}
// no-inf-no-nan-warning@+3 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}}
// no-inf-warning@+2 {{use of infinity is undefined behavior due to the currently enabled floating-point options}}
// no-inf-warning@+1 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}}
i = a == INFINITY;

// no-inf-no-nan-warning@+2 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}}
// no-inf-no-nan-warning@+4 {{use of infinity is undefined behavior due to the currently enabled floating-point options}}
// no-inf-no-nan-warning@+3 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}}
// no-inf-warning@+2 {{use of infinity is undefined behavior due to the currently enabled floating-point options}}
// no-inf-warning@+1 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}}
j = INFINITY == a;

Expand All @@ -107,11 +111,15 @@ int compareit(float a, float b) {
// no-nan-warning@+1 {{use of NaN via a macro is undefined behavior due to the currently enabled floating-point options}}
j = NAN == a;

// no-inf-no-nan-warning@+2 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}}
// no-inf-no-nan-warning@+4 {{use of infinity is undefined behavior due to the currently enabled floating-point options}}
// no-inf-no-nan-warning@+3 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}}
// no-inf-warning@+2 {{use of infinity is undefined behavior due to the currently enabled floating-point options}}
// no-inf-warning@+1 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}}
j = INFINITY <= a;

// no-inf-no-nan-warning@+2 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}}
// no-inf-no-nan-warning@+4 {{use of infinity is undefined behavior due to the currently enabled floating-point options}}
// no-inf-no-nan-warning@+3 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}}
// no-inf-warning@+2 {{use of infinity is undefined behavior due to the currently enabled floating-point options}}
// no-inf-warning@+1 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}}
j = INFINITY < a;

Expand Down Expand Up @@ -192,7 +200,9 @@ int compareit(float a, float b) {
// no-nan-warning@+1 {{use of NaN is undefined behavior due to the currently enabled floating-point options}}
j = isunorderedf(a, NAN);

// no-inf-no-nan-warning@+2 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}}
// no-inf-no-nan-warning@+4 {{use of infinity is undefined behavior due to the currently enabled floating-point options}}
// no-inf-no-nan-warning@+3 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}}
// no-inf-warning@+2 {{use of infinity is undefined behavior due to the currently enabled floating-point options}}
// no-inf-warning@+1 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}}
j = isunorderedf(a, INFINITY);

Expand All @@ -204,9 +214,11 @@ int compareit(float a, float b) {
// no-nan-warning@+1 {{use of NaN is undefined behavior due to the currently enabled floating-point options}}
i = std::isunordered(a, NAN);

// no-inf-no-nan-warning@+4 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}}
// no-inf-no-nan-warning@+3 {{use of NaN is undefined behavior due to the currently enabled floating-point options}}
// no-inf-warning@+2 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}}
// no-inf-no-nan-warning@+6 {{use of infinity is undefined behavior due to the currently enabled floating-point options}}
// no-inf-no-nan-warning@+5 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}}
// no-inf-no-nan-warning@+4 {{use of NaN is undefined behavior due to the currently enabled floating-point options}}
// no-inf-warning@+3 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}}
// no-inf-warning@+2 {{use of infinity is undefined behavior due to the currently enabled floating-point options}}
// no-nan-warning@+1 {{use of NaN is undefined behavior due to the currently enabled floating-point options}}
i = std::isunordered(a, INFINITY);

Expand Down
1 change: 1 addition & 0 deletions clang/test/SemaCXX/cxx1z-decomposition.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -std=c++17 -Wc++20-extensions -verify=expected %s
// RUN: %clang_cc1 -std=c++20 -Wpre-c++20-compat -verify=expected %s
// RUN: %clang_cc1 -std=c++20 -Wpre-c++20-compat -fexperimental-new-constant-interpreter -verify=expected %s

void use_from_own_init() {
auto [a] = a; // expected-error {{binding 'a' cannot appear in the initializer of its own decomposition declaration}}
Expand Down
9 changes: 9 additions & 0 deletions clang/test/SemaCXX/cxx2a-destroying-delete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,3 +187,12 @@ namespace delete_from_new {
#endif
}
}

namespace GH96191 {
struct S {};
struct T {
void operator delete(S) { } // expected-error {{first parameter of 'operator delete' must have type 'void *'}}
};

void foo(T *t) { delete t; }
}
1 change: 1 addition & 0 deletions clang/test/SemaCXX/new-delete-0x.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -triple=i686-pc-linux-gnu -std=c++11
// RUN: %clang_cc1 -fsyntax-only -verify %s -triple=i686-pc-linux-gnu -std=c++11 -fexperimental-new-constant-interpreter

using size_t = decltype(sizeof(0));
struct noreturn_t {} constexpr noreturn = {};
Expand Down
5 changes: 5 additions & 0 deletions clang/unittests/Tooling/ToolingTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,11 @@ TEST(runToolOnCode, TestSkipFunctionBody) {
EXPECT_FALSE(runToolOnCodeWithArgs(
std::make_unique<SkipBodyAction>(),
"template<typename T> int skipMeNot() { an_error_here }", Args2));

EXPECT_TRUE(runToolOnCodeWithArgs(
std::make_unique<SkipBodyAction>(),
"__inline __attribute__((__gnu_inline__)) void skipMe() {}",
{"--cuda-host-only", "-nocudainc", "-xcuda"}));
}

TEST(runToolOnCodeWithArgs, TestNoDepFile) {
Expand Down
46 changes: 24 additions & 22 deletions compiler-rt/lib/sanitizer_common/sanitizer_ptrauth.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,33 @@
#ifndef SANITIZER_PTRAUTH_H
#define SANITIZER_PTRAUTH_H

#if __has_feature(ptrauth_calls)
#include <ptrauth.h>
#if __has_feature(ptrauth_intrinsics)
# include <ptrauth.h>
#elif defined(__ARM_FEATURE_PAC_DEFAULT) && !defined(__APPLE__)
inline unsigned long ptrauth_strip(void* __value, unsigned int __key) {
// On the stack the link register is protected with Pointer
// Authentication Code when compiled with -mbranch-protection.
// Let's stripping the PAC unconditionally because xpaclri is in
// the NOP space so will do nothing when it is not enabled or not available.
unsigned long ret;
asm volatile(
"mov x30, %1\n\t"
"hint #7\n\t" // xpaclri
"mov %0, x30\n\t"
: "=r"(ret)
: "r"(__value)
: "x30");
return ret;
}
#define ptrauth_auth_data(__value, __old_key, __old_data) __value
#define ptrauth_string_discriminator(__string) ((int)0)
// On the stack the link register is protected with Pointer
// Authentication Code when compiled with -mbranch-protection.
// Let's stripping the PAC unconditionally because xpaclri is in
// the NOP space so will do nothing when it is not enabled or not available.
# define ptrauth_strip(__value, __key) \
({ \
unsigned long ret; \
asm volatile( \
"mov x30, %1\n\t" \
"hint #7\n\t" \
"mov %0, x30\n\t" \
"mov x30, xzr\n\t" \
: "=r"(ret) \
: "r"(__value) \
: "x30"); \
ret; \
})
# define ptrauth_auth_data(__value, __old_key, __old_data) __value
# define ptrauth_string_discriminator(__string) ((int)0)
#else
// Copied from <ptrauth.h>
#define ptrauth_strip(__value, __key) __value
#define ptrauth_auth_data(__value, __old_key, __old_data) __value
#define ptrauth_string_discriminator(__string) ((int)0)
# define ptrauth_strip(__value, __key) __value
# define ptrauth_auth_data(__value, __old_key, __old_data) __value
# define ptrauth_string_discriminator(__string) ((int)0)
#endif

#define STRIP_PAC_PC(pc) ((uptr)ptrauth_strip(pc, 0))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@

// Align counters and data to the maximum expected page size (16K).
// RUN: %clang -g -o %t %s \
// RUN: -Wl,-sectalign,__DATA,__pcnts,0x4000 \
// RUN: -Wl,-sectalign,__DATA,__pdata,0x4000
// RUN: -Wl,-sectalign,__DATA,__pcnts,0x1000 \
// RUN: -Wl,-sectalign,__DATA,__pdata,0x1000

// Create a 'profile' using mmap() and validate it.
// RUN: %run %t create %t.tmpfile
Expand All @@ -24,7 +24,7 @@

__attribute__((section("__DATA,__pcnts"))) int counters[] = {0xbad};
extern int cnts_start __asm("section$start$__DATA$__pcnts");
const size_t cnts_len = 0x4000;
const size_t cnts_len = 0x1000;

__attribute__((section("__DATA,__pdata"))) int data[] = {1, 2, 3};
extern int data_start __asm("section$start$__DATA$__pdata");
Expand All @@ -44,8 +44,8 @@ int create_tmpfile(char *path) {
return EXIT_FAILURE;
}

// Write the data first (at offset 0x4000, after the counters).
if (data_len != pwrite(fd, &data, data_len, 0x4000)) {
// Write the data first (at offset 0x1000, after the counters).
if (data_len != pwrite(fd, &data, data_len, cnts_len)) {
perror("write");
return EXIT_FAILURE;
}
Expand All @@ -55,8 +55,8 @@ int create_tmpfile(char *path) {
// Requirements (on Darwin):
// - &cnts_start must be page-aligned.
// - The length and offset-into-fd must be page-aligned.
int *counter_map = (int *)mmap(&cnts_start, 0x4000, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_SHARED, fd, 0);
int *counter_map = (int *)mmap(&cnts_start, cnts_len, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_SHARED, fd, 0);
if (counter_map != &cnts_start) {
perror("mmap");
return EXIT_FAILURE;
Expand Down Expand Up @@ -97,7 +97,7 @@ int validate_tmpfile(char *path) {
}

// Verify that the rest of the counters (after counter 9) are 0.
const int num_cnts = 0x4000 / sizeof(int);
const int num_cnts = cnts_len / sizeof(int);
for (int i = 10; i < num_cnts; ++i) {
if (buf[i] != 0) {
fprintf(stderr,
Expand Down Expand Up @@ -131,11 +131,12 @@ int main(int argc, char **argv) {
fprintf(stderr, "__pcnts is not page-aligned: 0x%lx.\n", cnts_start_int);
return EXIT_FAILURE;
}
if (data_start_int % pagesz != 0) {
fprintf(stderr, "__pdata is not page-aligned: 0x%lx.\n", data_start_int);
if (data_start_int % 0x1000 != 0) {
fprintf(stderr, "__pdata is not correctly aligned: 0x%lx.\n",
data_start_int);
return EXIT_FAILURE;
}
if (cnts_start_int + 0x4000 != data_start_int) {
if (cnts_start_int + 0x1000 != data_start_int) {
fprintf(stderr, "__pdata not ordered after __pcnts.\n");
return EXIT_FAILURE;
}
Expand Down
8 changes: 8 additions & 0 deletions flang/include/flang/Lower/ConvertVariable.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ using AggregateStoreMap = llvm::DenseMap<AggregateStoreKey, mlir::Value>;
void instantiateVariable(AbstractConverter &, const pft::Variable &var,
SymMap &symMap, AggregateStoreMap &storeMap);

/// Does this variable have a default initialization?
bool hasDefaultInitialization(const Fortran::semantics::Symbol &sym);

/// Call default initialization runtime routine to initialize \p var.
void defaultInitializeAtRuntime(Fortran::lower::AbstractConverter &converter,
const Fortran::semantics::Symbol &sym,
Fortran::lower::SymMap &symMap);

/// Create a fir::GlobalOp given a module variable definition. This is intended
/// to be used when lowering a module definition, not when lowering variables
/// used from a module. For used variables instantiateVariable must directly be
Expand Down
74 changes: 49 additions & 25 deletions flang/include/flang/Optimizer/CodeGen/CGOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,24 @@ def fircg_XEmboxOp : fircg_Op<"ext_embox", [AttrSizedOperandSegments]> {
unsigned getOutRank();

// The shape operands are mandatory and always start at 1.
unsigned shapeOffset() { return 1; }
unsigned shiftOffset() { return shapeOffset() + getShape().size(); }
unsigned sliceOffset() { return shiftOffset() + getShift().size(); }
unsigned subcomponentOffset() { return sliceOffset() + getSlice().size(); }
unsigned substrOffset() {
return subcomponentOffset() + getSubcomponent().size();
unsigned getShapeOperandIndex() { return 1; }
unsigned getShiftOperandIndex() {
return getShapeOperandIndex() + getShape().size();
}
unsigned lenParamOffset() { return substrOffset() + getSubstr().size(); }
unsigned getSourceBoxOffset() {
return lenParamOffset() + getLenParams().size();
unsigned getSliceOperandIndex() {
return getShiftOperandIndex() + getShift().size();
}
unsigned getSubcomponentOperandIndex() {
return getSliceOperandIndex() + getSlice().size();
}
unsigned getSubstrOperandIndex() {
return getSubcomponentOperandIndex() + getSubcomponent().size();
}
unsigned getLenParamOperandIndex() {
return getSubstrOperandIndex() + getSubstr().size();
}
unsigned getSourceBoxOperandIndex() {
return getLenParamOperandIndex() + getLenParams().size();
}
}];
}
Expand Down Expand Up @@ -135,12 +143,18 @@ def fircg_XReboxOp : fircg_Op<"ext_rebox", [AttrSizedOperandSegments]> {
// The rank of the result box
unsigned getOutRank();

unsigned shapeOffset() { return 1; }
unsigned shiftOffset() { return shapeOffset() + getShape().size(); }
unsigned sliceOffset() { return shiftOffset() + getShift().size(); }
unsigned subcomponentOffset() { return sliceOffset() + getSlice().size(); }
unsigned substrOffset() {
return subcomponentOffset() + getSubcomponent().size();
unsigned getShapeOperandIndex() { return 1; }
unsigned getShiftOperandIndex() {
return getShapeOperandIndex() + getShape().size();
}
unsigned getSliceOperandIndex() {
return getShiftOperandIndex() + getShift().size();
}
unsigned getSubcomponentOperandIndex() {
return getSliceOperandIndex() + getSlice().size();
}
unsigned getSubstrOperandIndex() {
return getSubcomponentOperandIndex() + getSubcomponent().size();
}
}];
}
Expand Down Expand Up @@ -193,14 +207,22 @@ def fircg_XArrayCoorOp : fircg_Op<"ext_array_coor", [AttrSizedOperandSegments]>
unsigned getRank();

// Shape is optional, but if it exists, it will be at offset 1.
unsigned shapeOffset() { return 1; }
unsigned shiftOffset() { return shapeOffset() + getShape().size(); }
unsigned sliceOffset() { return shiftOffset() + getShift().size(); }
unsigned subcomponentOffset() { return sliceOffset() + getSlice().size(); }
unsigned indicesOffset() {
return subcomponentOffset() + getSubcomponent().size();
}
unsigned lenParamsOffset() { return indicesOffset() + getIndices().size(); }
unsigned getShapeOperandIndex() { return 1; }
unsigned getShiftOperandIndex() {
return getShapeOperandIndex() + getShape().size();
}
unsigned getSliceOperandIndex() {
return getShiftOperandIndex() + getShift().size();
}
unsigned getSubcomponentOperandIndex() {
return getSliceOperandIndex() + getSlice().size();
}
unsigned getIndicesOperandIndex() {
return getSubcomponentOperandIndex() + getSubcomponent().size();
}
unsigned getLenParamsOperandIndex() {
return getIndicesOperandIndex() + getIndices().size();
}
}];
}

Expand Down Expand Up @@ -231,8 +253,10 @@ def fircg_XDeclareOp : fircg_Op<"ext_declare", [AttrSizedOperandSegments]> {

let extraClassDeclaration = [{
// Shape is optional, but if it exists, it will be at offset 1.
unsigned shapeOffset() { return 1; }
unsigned shiftOffset() { return shapeOffset() + getShape().size(); }
unsigned getShapeOperandIndex() { return 1; }
unsigned getShiftOperandIndex() {
return getShapeOperandIndex() + getShape().size();
}
}];
}

Expand Down
2 changes: 1 addition & 1 deletion flang/include/flang/Optimizer/Dialect/FIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -817,7 +817,7 @@ def fir_EmboxOp : fir_Op<"embox", [NoMemoryEffect, AttrSizedOperandSegments]> {
let extraClassDeclaration = [{
bool hasLenParams() { return !getTypeparams().empty(); }
unsigned numLenParams() { return getTypeparams().size(); }
unsigned getSourceBoxOffset() {
unsigned getSourceBoxOperandIndex() {
return 1 + (getShape() ? 1 : 0) + (getSlice() ? 1 : 0)
+ numLenParams();
}
Expand Down
23 changes: 12 additions & 11 deletions flang/lib/Lower/ConvertVariable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ static mlir::Value genScalarValue(Fortran::lower::AbstractConverter &converter,
}

/// Does this variable have a default initialization?
static bool hasDefaultInitialization(const Fortran::semantics::Symbol &sym) {
bool Fortran::lower::hasDefaultInitialization(
const Fortran::semantics::Symbol &sym) {
if (sym.has<Fortran::semantics::ObjectEntityDetails>() && sym.size())
if (!Fortran::semantics::IsAllocatableOrPointer(sym))
if (const Fortran::semantics::DeclTypeSpec *declTypeSpec = sym.GetType())
Expand Down Expand Up @@ -353,7 +354,7 @@ static mlir::Value genComponentDefaultInit(
// global constructor since this has no runtime cost.
componentValue = fir::factory::createUnallocatedBox(
builder, loc, componentTy, std::nullopt);
} else if (hasDefaultInitialization(component)) {
} else if (Fortran::lower::hasDefaultInitialization(component)) {
// Component type has default initialization.
componentValue = genDefaultInitializerValue(converter, loc, component,
componentTy, stmtCtx);
Expand Down Expand Up @@ -556,7 +557,7 @@ static fir::GlobalOp defineGlobal(Fortran::lower::AbstractConverter &converter,
builder.createConvert(loc, symTy, fir::getBase(initVal));
builder.create<fir::HasValueOp>(loc, castTo);
});
} else if (hasDefaultInitialization(sym)) {
} else if (Fortran::lower::hasDefaultInitialization(sym)) {
Fortran::lower::createGlobalInitialization(
builder, global, [&](fir::FirOpBuilder &builder) {
Fortran::lower::StatementContext stmtCtx(
Expand Down Expand Up @@ -752,17 +753,15 @@ mustBeDefaultInitializedAtRuntime(const Fortran::lower::pft::Variable &var) {
return true;
// Local variables (including function results), and intent(out) dummies must
// be default initialized at runtime if their type has default initialization.
return hasDefaultInitialization(sym);
return Fortran::lower::hasDefaultInitialization(sym);
}

/// Call default initialization runtime routine to initialize \p var.
static void
defaultInitializeAtRuntime(Fortran::lower::AbstractConverter &converter,
const Fortran::lower::pft::Variable &var,
Fortran::lower::SymMap &symMap) {
void Fortran::lower::defaultInitializeAtRuntime(
Fortran::lower::AbstractConverter &converter,
const Fortran::semantics::Symbol &sym, Fortran::lower::SymMap &symMap) {
fir::FirOpBuilder &builder = converter.getFirOpBuilder();
mlir::Location loc = converter.getCurrentLocation();
const Fortran::semantics::Symbol &sym = var.getSymbol();
fir::ExtendedValue exv = converter.getSymbolExtendedValue(sym, &symMap);
if (Fortran::semantics::IsOptional(sym)) {
// 15.5.2.12 point 3, absent optional dummies are not initialized.
Expand Down Expand Up @@ -927,7 +926,8 @@ static void instantiateLocal(Fortran::lower::AbstractConverter &converter,
if (needDummyIntentoutFinalization(var))
finalizeAtRuntime(converter, var, symMap);
if (mustBeDefaultInitializedAtRuntime(var))
defaultInitializeAtRuntime(converter, var, symMap);
Fortran::lower::defaultInitializeAtRuntime(converter, var.getSymbol(),
symMap);
if (Fortran::semantics::NeedCUDAAlloc(var.getSymbol())) {
auto *builder = &converter.getFirOpBuilder();
mlir::Location loc = converter.getCurrentLocation();
Expand Down Expand Up @@ -1168,7 +1168,8 @@ static void instantiateAlias(Fortran::lower::AbstractConverter &converter,
// do not try optimizing this to single default initializations of
// the equivalenced storages. Keep lowering simple.
if (mustBeDefaultInitializedAtRuntime(var))
defaultInitializeAtRuntime(converter, var, symMap);
Fortran::lower::defaultInitializeAtRuntime(converter, var.getSymbol(),
symMap);
}

//===--------------------------------------------------------------===//
Expand Down
6 changes: 6 additions & 0 deletions flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "DataSharingProcessor.h"

#include "Utils.h"
#include "flang/Lower/ConvertVariable.h"
#include "flang/Lower/PFTBuilder.h"
#include "flang/Lower/SymbolMap.h"
#include "flang/Optimizer/Builder/HLFIRTools.h"
Expand Down Expand Up @@ -117,6 +118,11 @@ void DataSharingProcessor::cloneSymbol(const semantics::Symbol *sym) {
bool success = converter.createHostAssociateVarClone(*sym);
(void)success;
assert(success && "Privatization failed due to existing binding");

bool isFirstPrivate = sym->test(semantics::Symbol::Flag::OmpFirstPrivate);
if (!isFirstPrivate &&
Fortran::lower::hasDefaultInitialization(sym->GetUltimate()))
Fortran::lower::defaultInitializeAtRuntime(converter, *sym, *symTable);
}

void DataSharingProcessor::copyFirstPrivateSymbol(
Expand Down
Loading