54 changes: 54 additions & 0 deletions bolt/test/X86/linux-parainstructions.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# REQUIRES: system-linux

## Check that BOLT correctly parses the Linux kernel .parainstructions section.

# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o
# RUN: %clang %cflags -nostdlib %t.o -o %t.exe \
# RUN: -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr,--no-pie

## Verify paravirtual bindings to instructions.

# RUN: llvm-bolt %t.exe --print-normalized -o %t.out | FileCheck %s

# CHECK: BOLT-INFO: Linux kernel binary detected
# CHECK: BOLT-INFO: parsed 2 paravirtual patch sites

.rodata
fptr:
.quad 0

.text
.globl _start
.type _start, %function
_start:
# CHECK: Binary Function "_start"
nop
.L1:
call *fptr(%rip)
# CHECK: call
# CHECK-SAME: ParaSite: 1
nop
.L2:
call *fptr(%rip)
# CHECK: call
# CHECK-SAME: ParaSite: 2
ret
.size _start, .-_start


## Paravirtual patch sites.
.section .parainstructions,"a",@progbits

.balign 8
.quad .L1 # instruction
.byte 1 # type
.byte 7 # length

.balign 8
.quad .L2 # instruction
.byte 1 # type
.byte 7 # length

## Fake Linux Kernel sections.
.section __ksymtab,"a",@progbits
.section __ksymtab_gpl,"a",@progbits
2 changes: 1 addition & 1 deletion bolt/test/X86/pt_gnu_relro.s
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# Check that BOLT recognizes PT_GNU_RELRO segment and marks respective sections
# accordingly.

# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %s -o %t.o -relax-relocations
# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %s -o %t.o
# RUN: ld.lld %t.o -o %t.exe -q --no-relax
# RUN: llvm-readelf -We %t.exe | FileCheck --check-prefix=READELF %s
# Unfortunately there's no direct way to extract a segment to section mapping
Expand Down
2 changes: 1 addition & 1 deletion bolt/tools/merge-fdata/merge-fdata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ void mergeLegacyProfiles(const SmallVectorImpl<std::string> &Filenames) {
// least 4 tasks.
ThreadPoolStrategy S = optimal_concurrency(
std::max(Filenames.size() / 4, static_cast<size_t>(1)));
ThreadPool Pool(S);
DefaultThreadPool Pool(S);
DenseMap<llvm::thread::id, ProfileTy> ParsedProfiles(
Pool.getMaxConcurrency());
for (const auto &Filename : Filenames)
Expand Down
2 changes: 1 addition & 1 deletion clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ Example usage for a project using a compile commands database:
Error = false;
llvm::sys::Mutex IndexMutex;
// ExecutorConcurrency is a flag exposed by AllTUsExecution.h
llvm::ThreadPool Pool(llvm::hardware_concurrency(ExecutorConcurrency));
llvm::DefaultThreadPool Pool(llvm::hardware_concurrency(ExecutorConcurrency));
for (auto &Group : USRToBitcode) {
Pool.async([&]() {
std::vector<std::unique_ptr<doc::Info>> Infos;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ bool Merge(llvm::StringRef MergeDir, llvm::StringRef OutputFile) {

// Load all symbol files in MergeDir.
{
llvm::ThreadPool Pool;
llvm::DefaultThreadPool Pool;
for (llvm::sys::fs::directory_iterator Dir(MergeDir, EC), DirEnd;
Dir != DirEnd && !EC; Dir.increment(EC)) {
// Parse YAML files in parallel.
Expand Down
20 changes: 15 additions & 5 deletions clang-tools-extra/clang-tidy/bugprone/AssertSideEffectCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,26 @@ AST_MATCHER_P2(Expr, hasSideEffect, bool, CheckFunctionCalls,
}

if (const auto *CExpr = dyn_cast<CallExpr>(E)) {
bool Result = CheckFunctionCalls;
if (!CheckFunctionCalls)
return false;
if (const auto *FuncDecl = CExpr->getDirectCallee()) {
if (FuncDecl->getDeclName().isIdentifier() &&
IgnoredFunctionsMatcher.matches(*FuncDecl, Finder,
Builder)) // exceptions come here
Result = false;
else if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(FuncDecl))
Result &= !MethodDecl->isConst();
return false;
for (size_t I = 0; I < FuncDecl->getNumParams(); I++) {
const ParmVarDecl *P = FuncDecl->getParamDecl(I);
const Expr *ArgExpr =
I < CExpr->getNumArgs() ? CExpr->getArg(I) : nullptr;
const QualType PT = P->getType().getCanonicalType();
if (ArgExpr && !ArgExpr->isXValue() && PT->isReferenceType() &&
!PT.getNonReferenceType().isConstQualified())
return true;
}
if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(FuncDecl))
return !MethodDecl->isConst();
}
return Result;
return true;
}

return isa<CXXNewExpr>(E) || isa<CXXDeleteExpr>(E) || isa<CXXThrowExpr>(E);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,12 @@ void MissingStdForwardCheck::registerMatchers(MatchFinder *Finder) {

auto ForwardCallMatcher = callExpr(
callExpr().bind("call"), argumentCountIs(1),
hasArgument(
0, declRefExpr(to(
varDecl(optionally(equalsBoundNode("param"))).bind("var")))),
forCallable(anyOf(equalsBoundNode("func"), CapturedInLambda)),
hasArgument(0, declRefExpr(to(varDecl().bind("var")))),
forCallable(
anyOf(allOf(equalsBoundNode("func"),
functionDecl(hasAnyParameter(parmVarDecl(allOf(
equalsBoundNode("param"), equalsBoundNode("var")))))),
CapturedInLambda)),
callee(unresolvedLookupExpr(hasAnyDeclaration(
namedDecl(hasUnderlyingDecl(hasName("::std::forward")))))),

Expand Down
9 changes: 2 additions & 7 deletions clang-tools-extra/clangd/ClangdServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -551,15 +551,10 @@ void ClangdServer::formatOnType(PathRef File, Position Pos,
auto Action = [File = File.str(), Code = std::move(*Code),
TriggerText = TriggerText.str(), CursorPos = *CursorPos,
CB = std::move(CB), this]() mutable {
auto Style = format::getStyle(format::DefaultFormatStyle, File,
format::DefaultFallbackStyle, Code,
TFS.view(/*CWD=*/std::nullopt).get());
if (!Style)
return CB(Style.takeError());

auto Style = getFormatStyleForFile(File, Code, TFS);
std::vector<TextEdit> Result;
for (const tooling::Replacement &R :
formatIncremental(Code, CursorPos, TriggerText, *Style))
formatIncremental(Code, CursorPos, TriggerText, Style))
Result.push_back(replacementToEdit(Code, R));
return CB(Result);
};
Expand Down
4 changes: 2 additions & 2 deletions clang-tools-extra/clangd/FindSymbols.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,8 @@ std::string getSymbolDetail(ASTContext &Ctx, const NamedDecl &ND) {
std::optional<DocumentSymbol> declToSym(ASTContext &Ctx, const NamedDecl &ND) {
auto &SM = Ctx.getSourceManager();

SourceLocation BeginLoc = SM.getFileLoc(ND.getBeginLoc());
SourceLocation EndLoc = SM.getFileLoc(ND.getEndLoc());
SourceLocation BeginLoc = ND.getBeginLoc();
SourceLocation EndLoc = ND.getEndLoc();
const auto SymbolRange =
toHalfOpenFileRange(SM, Ctx.getLangOpts(), {BeginLoc, EndLoc});
if (!SymbolRange)
Expand Down
15 changes: 5 additions & 10 deletions clang-tools-extra/clangd/IncludeCleaner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,21 +111,15 @@ bool mayConsiderUnused(const Inclusion &Inc, ParsedAST &AST,

std::vector<Diag> generateMissingIncludeDiagnostics(
ParsedAST &AST, llvm::ArrayRef<MissingIncludeDiagInfo> MissingIncludes,
llvm::StringRef Code, HeaderFilter IgnoreHeaders) {
llvm::StringRef Code, HeaderFilter IgnoreHeaders, const ThreadsafeFS &TFS) {
std::vector<Diag> Result;
const SourceManager &SM = AST.getSourceManager();
const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID());

auto FileStyle = format::getStyle(
format::DefaultFormatStyle, AST.tuPath(), format::DefaultFallbackStyle,
Code, &SM.getFileManager().getVirtualFileSystem());
if (!FileStyle) {
elog("Couldn't infer style", FileStyle.takeError());
FileStyle = format::getLLVMStyle();
}
auto FileStyle = getFormatStyleForFile(AST.tuPath(), Code, TFS);

tooling::HeaderIncludes HeaderIncludes(AST.tuPath(), Code,
FileStyle->IncludeStyle);
FileStyle.IncludeStyle);
for (const auto &SymbolWithMissingInclude : MissingIncludes) {
llvm::StringRef ResolvedPath =
SymbolWithMissingInclude.Providers.front().resolvedPath();
Expand Down Expand Up @@ -459,14 +453,15 @@ bool isPreferredProvider(const Inclusion &Inc,
std::vector<Diag>
issueIncludeCleanerDiagnostics(ParsedAST &AST, llvm::StringRef Code,
const IncludeCleanerFindings &Findings,
const ThreadsafeFS &TFS,
HeaderFilter IgnoreHeaders) {
trace::Span Tracer("IncludeCleaner::issueIncludeCleanerDiagnostics");
std::vector<Diag> UnusedIncludes = generateUnusedIncludeDiagnostics(
AST.tuPath(), Findings.UnusedIncludes, Code, IgnoreHeaders);
std::optional<Fix> RemoveAllUnused = removeAllUnusedIncludes(UnusedIncludes);

std::vector<Diag> MissingIncludeDiags = generateMissingIncludeDiagnostics(
AST, Findings.MissingIncludes, Code, IgnoreHeaders);
AST, Findings.MissingIncludes, Code, IgnoreHeaders, TFS);
std::optional<Fix> AddAllMissing = addAllMissingIncludes(MissingIncludeDiags);

std::optional<Fix> FixAll;
Expand Down
1 change: 1 addition & 0 deletions clang-tools-extra/clangd/IncludeCleaner.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ using HeaderFilter = llvm::ArrayRef<std::function<bool(llvm::StringRef)>>;
std::vector<Diag>
issueIncludeCleanerDiagnostics(ParsedAST &AST, llvm::StringRef Code,
const IncludeCleanerFindings &Findings,
const ThreadsafeFS &TFS,
HeaderFilter IgnoreHeader = {});

/// Affects whether standard library includes should be considered for
Expand Down
7 changes: 4 additions & 3 deletions clang-tools-extra/clangd/ParsedAST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,8 @@ void applyWarningOptions(llvm::ArrayRef<std::string> ExtraArgs,
}
}

std::vector<Diag> getIncludeCleanerDiags(ParsedAST &AST, llvm::StringRef Code) {
std::vector<Diag> getIncludeCleanerDiags(ParsedAST &AST, llvm::StringRef Code,
const ThreadsafeFS &TFS) {
auto &Cfg = Config::current();
if (Cfg.Diagnostics.SuppressAll)
return {};
Expand All @@ -377,7 +378,7 @@ std::vector<Diag> getIncludeCleanerDiags(ParsedAST &AST, llvm::StringRef Code) {
Findings.MissingIncludes.clear();
if (SuppressUnused)
Findings.UnusedIncludes.clear();
return issueIncludeCleanerDiagnostics(AST, Code, Findings,
return issueIncludeCleanerDiagnostics(AST, Code, Findings, TFS,
Cfg.Diagnostics.Includes.IgnoreHeader);
}

Expand Down Expand Up @@ -741,7 +742,7 @@ ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs,
std::move(Clang), std::move(Action), std::move(Tokens),
std::move(Macros), std::move(Marks), std::move(ParsedDecls),
std::move(Diags), std::move(Includes), std::move(PI));
llvm::move(getIncludeCleanerDiags(Result, Inputs.Contents),
llvm::move(getIncludeCleanerDiags(Result, Inputs.Contents, *Inputs.TFS),
std::back_inserter(Result.Diags));
return std::move(Result);
}
Expand Down
4 changes: 4 additions & 0 deletions clang-tools-extra/clangd/refactor/Rename.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1062,6 +1062,10 @@ llvm::Expected<RenameResult> rename(const RenameInputs &RInputs) {
return makeError(ReasonToReject::AmbiguousSymbol);

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

std::string Placeholder = getName(RenameDecl);
auto Invalid = checkName(RenameDecl, RInputs.NewName, Placeholder);
if (Invalid)
Expand Down
17 changes: 17 additions & 0 deletions clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1462,6 +1462,23 @@ TEST(SignatureHelpTest, FunctionPointers) {
typedef void (__stdcall *fn)(int x, int y);
fn foo;
int main() { foo(^); }
)cpp",
// Field of function pointer type
R"cpp(
struct S {
void (*foo)(int x, int y);
};
S s;
int main() { s.foo(^); }
)cpp",
// Field of function pointer typedef type
R"cpp(
typedef void (*fn)(int x, int y);
struct S {
fn foo;
};
S s;
int main() { s.foo(^); }
)cpp"};
for (auto Test : Tests)
EXPECT_THAT(signatures(Test).signatures,
Expand Down
9 changes: 8 additions & 1 deletion clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,9 @@ TEST(DocumentSymbols, RangeFromMacro) {
$fullDef[[FF3() {
int var = 42;
}]]
#define FF4(name) int name = 0
$FooRange[[FF4($FooSelectionRange[[foo]])]];
)");
TU.Code = Main.code().str();
EXPECT_THAT(
Expand All @@ -766,7 +769,11 @@ TEST(DocumentSymbols, RangeFromMacro) {
AllOf(withName("FF3"), withDetail("()"),
symRange(Main.range("fullDef")),
children(AllOf(withName("waldo"), withDetail("void ()"),
symRange(Main.range("fullDef")))))));
symRange(Main.range("fullDef"))))),
AllOf(
withName("FF4"), withDetail("(foo)"),
children(AllOf(withName("foo"), symRange(Main.range("FooRange")),
symNameRange(Main.range("FooSelectionRange")))))));
}

TEST(DocumentSymbols, FuncTemplates) {
Expand Down
14 changes: 7 additions & 7 deletions clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ TEST(IncludeCleaner, GenerateMissingHeaderDiags) {
auto Findings = computeIncludeCleanerFindings(AST);
Findings.UnusedIncludes.clear();
std::vector<clangd::Diag> Diags = issueIncludeCleanerDiagnostics(
AST, TU.Code, Findings,
AST, TU.Code, Findings, MockFS(),
{[](llvm::StringRef Header) { return Header.ends_with("buzz.h"); }});
EXPECT_THAT(
Diags,
Expand Down Expand Up @@ -505,8 +505,8 @@ TEST(IncludeCleaner, BatchFix) {
)cpp";
auto AST = TU.build();
EXPECT_THAT(
issueIncludeCleanerDiagnostics(AST, TU.Code,
computeIncludeCleanerFindings(AST)),
issueIncludeCleanerDiagnostics(
AST, TU.Code, computeIncludeCleanerFindings(AST), MockFS()),
UnorderedElementsAre(withFix({FixMessage("#include \"foo.h\""),
FixMessage("fix all includes")}),
withFix({FixMessage("remove #include directive"),
Expand All @@ -520,8 +520,8 @@ TEST(IncludeCleaner, BatchFix) {
)cpp";
AST = TU.build();
EXPECT_THAT(
issueIncludeCleanerDiagnostics(AST, TU.Code,
computeIncludeCleanerFindings(AST)),
issueIncludeCleanerDiagnostics(
AST, TU.Code, computeIncludeCleanerFindings(AST), MockFS()),
UnorderedElementsAre(withFix({FixMessage("#include \"foo.h\""),
FixMessage("fix all includes")}),
withFix({FixMessage("remove #include directive"),
Expand All @@ -539,8 +539,8 @@ TEST(IncludeCleaner, BatchFix) {
)cpp";
AST = TU.build();
EXPECT_THAT(
issueIncludeCleanerDiagnostics(AST, TU.Code,
computeIncludeCleanerFindings(AST)),
issueIncludeCleanerDiagnostics(
AST, TU.Code, computeIncludeCleanerFindings(AST), MockFS()),
UnorderedElementsAre(withFix({FixMessage("#include \"foo.h\""),
FixMessage("add all missing includes"),
FixMessage("fix all includes")}),
Expand Down
7 changes: 6 additions & 1 deletion clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ New check aliases
Changes in existing checks
^^^^^^^^^^^^^^^^^^^^^^^^^^

- Improved :doc:`bugprone-assert-side-effect
<clang-tidy/checks/bugprone/assert-side-effect>` check by detecting side
effect from calling a method with non-const reference parameters.

- Improved :doc:`bugprone-non-zero-enum-to-bool-conversion
<clang-tidy/checks/bugprone/non-zero-enum-to-bool-conversion>` check by
eliminating false positives resulting from direct usage of bitwise operators
Expand Down Expand Up @@ -156,7 +160,8 @@ Changes in existing checks

- Improved :doc:`cppcoreguidelines-missing-std-forward
<clang-tidy/checks/cppcoreguidelines/missing-std-forward>` check by no longer
giving false positives for deleted functions.
giving false positives for deleted functions and fix false negative when some
parameters are forwarded, but other aren't.

- Cleaned up :doc:`cppcoreguidelines-prefer-member-initializer
<clang-tidy/checks/cppcoreguidelines/prefer-member-initializer>`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,27 @@ int main() {

return 0;
}

namespace parameter_anaylysis {

struct S {
bool value(int) const;
bool leftValueRef(int &) const;
bool constRef(int const &) const;
bool rightValueRef(int &&) const;
};

void foo() {
S s{};
int i = 0;
assert(s.value(0));
assert(s.value(i));
assert(s.leftValueRef(i));
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: side effect in assert() condition discarded in release builds
assert(s.constRef(0));
assert(s.constRef(i));
assert(s.rightValueRef(0));
assert(s.rightValueRef(static_cast<int &&>(i)));
}

} // namespace parameter_anaylysis
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,16 @@ void lambda_value_capture_copy(T&& t) {
[&,t]() { T other = std::forward<T>(t); };
}

template <typename X>
void use(const X &x) {}

template <typename X, typename Y>
void foo(X &&x, Y &&y) {
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: forwarding reference parameter 'y' is never forwarded inside the function body [cppcoreguidelines-missing-std-forward]
use(std::forward<X>(x));
use(y);
}

} // namespace positive_cases

namespace negative_cases {
Expand Down
2 changes: 1 addition & 1 deletion clang/CodeOwners.rst
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ Analysis & CFG
Experimental new constant interpreter
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Timm Bäder
| tbaeder@redhat.com (email), tbaeder (Phabricator), tbaederr (GitHub)
| tbaeder\@redhat.com (email), tbaeder (Phabricator), tbaederr (GitHub), tbaeder (Discourse), tbaeder (Discord)

Modules & serialization
Expand Down
33 changes: 33 additions & 0 deletions clang/cmake/caches/Fuchsia-stage2.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,39 @@ if(FUCHSIA_SDK)
set(LLVM_RUNTIME_MULTILIB_hwasan+noexcept_TARGETS "aarch64-unknown-fuchsia;riscv64-unknown-fuchsia" CACHE STRING "")
endif()

foreach(target armv6m-unknown-eabi)
list(APPEND BUILTIN_TARGETS "${target}")
set(BUILTINS_${target}_CMAKE_SYSTEM_NAME Generic CACHE STRING "")
set(BUILTINS_${target}_CMAKE_SYSTEM_PROCESSOR arm CACHE STRING "")
set(BUILTINS_${target}_CMAKE_SYSROOT "" CACHE STRING "")
set(BUILTINS_${target}_CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "")
foreach(lang C;CXX;ASM)
set(BUILTINS_${target}_CMAKE_${lang}_FLAGS "--target=${target} -mcpu=cortex-m0plus -mthumb" CACHE STRING "")
endforeach()
foreach(type SHARED;MODULE;EXE)
set(BUILTINS_${target}_CMAKE_${type}_LINKER_FLAGS "-fuse-ld=lld" CACHE STRING "")
endforeach()
set(BUILTINS_${target}_COMPILER_RT_BAREMETAL_BUILD ON CACHE BOOL "")

list(APPEND RUNTIME_TARGETS "${target}")
set(RUNTIMES_${target}_CMAKE_SYSTEM_NAME Generic CACHE STRING "")
set(RUNTIMES_${target}_CMAKE_SYSTEM_PROCESSOR arm CACHE STRING "")
set(RUNTIMES_${target}_CMAKE_SYSROOT "" CACHE STRING "")
set(RUNTIMES_${target}_CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "")
set(RUNTIMES_${target}_CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY CACHE STRING "")
foreach(lang C;CXX;ASM)
set(RUNTIMES_${target}_CMAKE_${lang}_FLAGS "--target=${target} -mcpu=cortex-m0plus -mthumb" CACHE STRING "")
endforeach()
foreach(type SHARED;MODULE;EXE)
set(RUNTIMES_${target}_CMAKE_${type}_LINKER_FLAGS "-fuse-ld=lld" CACHE STRING "")
endforeach()
set(RUNTIMES_${target}_LLVM_LIBC_FULL_BUILD ON CACHE BOOL "")
set(RUNTIMES_${target}_LIBC_ENABLE_USE_BY_CLANG ON CACHE BOOL "")
set(RUNTIMES_${target}_LLVM_INCLUDE_TESTS OFF CACHE BOOL "")
set(RUNTIMES_${target}_LLVM_ENABLE_ASSERTIONS OFF CACHE BOOL "")
set(RUNTIMES_${target}_LLVM_ENABLE_RUNTIMES "libc" CACHE STRING "")
endforeach()

foreach(target riscv32-unknown-elf)
list(APPEND BUILTIN_TARGETS "${target}")
set(BUILTINS_${target}_CMAKE_SYSTEM_NAME Generic CACHE STRING "")
Expand Down
28 changes: 28 additions & 0 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2799,6 +2799,34 @@ counter's true frequency will need to be provided by the user.
Query for this feature with ``__has_builtin(__builtin_readsteadycounter)``.
``__builtin_cpu_supports``
--------------------------
**Syntax**:
.. code-block:: c++
int __builtin_cpu_supports(const char *features);
**Example of Use:**:
.. code-block:: c++
if (__builtin_cpu_supports("sve"))
sve_code();
**Description**:
The ``__builtin_cpu_supports`` function detects if the run-time CPU supports
features specified in string argument. It returns a positive integer if all
features are supported and 0 otherwise. Feature names are target specific. On
AArch64 features are combined using ``+`` like this
``__builtin_cpu_supports("flagm+sha3+lse+rcpc2+fcma+memtag+bti+sme2")``.
If a feature name is not supported, Clang will issue a warning and replace
builtin by the constant 0.
Query for this feature with ``__has_builtin(__builtin_cpu_supports)``.
``__builtin_dump_struct``
-------------------------
Expand Down
31 changes: 31 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,19 @@ C++20 Feature Support
- Implemented the `__is_layout_compatible` intrinsic to support
`P0466R5: Layout-compatibility and Pointer-interconvertibility Traits <https://wg21.link/P0466R5>`_.

- Clang now implements [module.import]p7 fully. Clang now will import module
units transitively for the module units coming from the same module of the
current module units.
Fixes `#84002 <https://github.com/llvm/llvm-project/issues/84002>`_.

C++23 Feature Support
^^^^^^^^^^^^^^^^^^^^^

- Implemented `P2718R0: Lifetime extension in range-based for loops <https://wg21.link/P2718R0>`_. Also
materialize temporary object which is a prvalue in discarded-value expression.

- Implemented `P2448R2: Relaxing some constexpr restrictions <https://wg21.link/P2448R2>`_.

C++2c Feature Support
^^^^^^^^^^^^^^^^^^^^^

Expand Down Expand Up @@ -138,6 +145,9 @@ C23 Feature Support
macros typically exposed from ``<inttypes.h>``, such as ``PRIb8``.
(`#81896: <https://github.com/llvm/llvm-project/issues/81896>`_).

- Clang now supports `N3018 The constexpr specifier for object definitions`
<https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3018.htm>`_.

Non-comprehensive list of changes in this release
-------------------------------------------------

Expand All @@ -150,6 +160,10 @@ Non-comprehensive list of changes in this release
New Compiler Flags
------------------

- ``-Wmissing-designated-field-initializers``, grouped under ``-Wmissing-field-initializers``.
This diagnostic can be disabled to make ``-Wmissing-field-initializers`` behave
like it did before Clang 18.x. Fixes (`#56628 <https://github.com/llvm/llvm-project/issues/68933>`_)

Deprecated Compiler Flags
-------------------------

Expand Down Expand Up @@ -177,6 +191,9 @@ Improvements to Clang's diagnostics
- The ``-Wshorten-64-to-32`` diagnostic is now grouped under ``-Wimplicit-int-conversion`` instead
of ``-Wconversion``. Fixes #GH69444.

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

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

- Added diagnostics for C11 keywords being incompatible with language standards
Expand Down Expand Up @@ -265,6 +282,8 @@ Bug Fixes to C++ Support
- Fix a crash when trying to call a varargs function that also has an explicit object parameter. (#GH80971)
- Fixed a bug where abbreviated function templates would append their invented template parameters to
an empty template parameter lists.
- Fix parsing of abominable function types inside type traits.
Fixes (`#77585 <https://github.com/llvm/llvm-project/issues/77585>`_)
- Clang now classifies aggregate initialization in C++17 and newer as constant
or non-constant more accurately. Previously, only a subset of the initializer
elements were considered, misclassifying some initializers as constant. Partially fixes
Expand Down Expand Up @@ -298,6 +317,18 @@ Bug Fixes to C++ Support
- Fixed an issue where an attribute on a declarator would cause the attribute to
be destructed prematurely. This fixes a pair of Chromium that were brought to
our attention by an attempt to fix in (#GH77703). Fixes (#GH83385).
- Fix evaluation of some immediate calls in default arguments.
Fixes (#GH80630)
- Fix a crash when an explicit template argument list is used with a name for which lookup
finds a non-template function and a dependent using declarator.
- Fixed an issue where the ``RequiresExprBody`` was involved in the lambda dependency
calculation. (#GH56556), (#GH82849).
- Fix a bug where overload resolution falsely reported an ambiguity when it was comparing
a member-function against a non member function or a member-function with an
explicit object parameter against a member function with no explicit object parameter
when one of the function had more specialized templates.
Fixes (`#82509 <https://github.com/llvm/llvm-project/issues/82509>`_)
and (`#74494 <https://github.com/llvm/llvm-project/issues/74494>`_)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
16 changes: 10 additions & 6 deletions clang/include/clang/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -4419,15 +4419,15 @@ class FileScopeAsmDecl : public Decl {
///
/// \note This is used in libInterpreter, clang -cc1 -fincremental-extensions
/// and in tools such as clang-repl.
class TopLevelStmtDecl : public Decl {
class TopLevelStmtDecl : public Decl, public DeclContext {
friend class ASTDeclReader;
friend class ASTDeclWriter;

Stmt *Statement = nullptr;
bool IsSemiMissing = false;

TopLevelStmtDecl(DeclContext *DC, SourceLocation L, Stmt *S)
: Decl(TopLevelStmt, DC, L), Statement(S) {}
: Decl(TopLevelStmt, DC, L), DeclContext(TopLevelStmt), Statement(S) {}

virtual void anchor();

Expand All @@ -4438,15 +4438,19 @@ class TopLevelStmtDecl : public Decl {
SourceRange getSourceRange() const override LLVM_READONLY;
Stmt *getStmt() { return Statement; }
const Stmt *getStmt() const { return Statement; }
void setStmt(Stmt *S) {
assert(IsSemiMissing && "Operation supported for printing values only!");
Statement = S;
}
void setStmt(Stmt *S);
bool isSemiMissing() const { return IsSemiMissing; }
void setSemiMissing(bool Missing = true) { IsSemiMissing = Missing; }

static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == TopLevelStmt; }

static DeclContext *castToDeclContext(const TopLevelStmtDecl *D) {
return static_cast<DeclContext *>(const_cast<TopLevelStmtDecl *>(D));
}
static TopLevelStmtDecl *castFromDeclContext(const DeclContext *DC) {
return static_cast<TopLevelStmtDecl *>(const_cast<DeclContext *>(DC));
}
};

/// Represents a block literal declaration, which is like an
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/AST/DeclBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -2120,6 +2120,7 @@ class DeclContext {
case Decl::Block:
case Decl::Captured:
case Decl::ObjCMethod:
case Decl::TopLevelStmt:
return true;
default:
return getDeclKind() >= Decl::firstFunction &&
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/AST/DeclOpenMP.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//===- DeclOpenMP.h - Classes for representing OpenMP directives -*- C++ -*-===//
//===- DeclOpenMP.h - Classes for representing OpenMP directives -*- C++ -*-==//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
Expand Down
13 changes: 12 additions & 1 deletion clang/include/clang/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -1875,6 +1875,17 @@ class StringLiteral final
llvm_unreachable("Unsupported character width!");
}

// Get code unit but preserve sign info.
int64_t getCodeUnitS(size_t I, uint64_t BitWidth) const {
int64_t V = getCodeUnit(I);
if (isOrdinary() || isWide()) {
unsigned Width = getCharByteWidth() * BitWidth;
llvm::APInt AInt(Width, (uint64_t)V);
V = AInt.getSExtValue();
}
return V;
}

unsigned getByteLength() const { return getCharByteWidth() * getLength(); }
unsigned getLength() const { return *getTrailingObjects<unsigned>(); }
unsigned getCharByteWidth() const { return StringLiteralBits.CharByteWidth; }
Expand Down Expand Up @@ -5832,7 +5843,7 @@ class GenericSelectionExpr final
std::conditional_t<Const, const Stmt *const *, Stmt **>;
using TSIPtrPtrTy = std::conditional_t<Const, const TypeSourceInfo *const *,
TypeSourceInfo **>;
StmtPtrPtrTy E; // = nullptr; FIXME: Once support for gcc 4.8 is dropped.
StmtPtrPtrTy E = nullptr;
TSIPtrPtrTy TSI; // Kept in sync with E.
unsigned Offset = 0, SelectedOffset = 0;
AssociationIteratorTy(StmtPtrPtrTy E, TSIPtrPtrTy TSI, unsigned Offset,
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/AST/ParentMapContext.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//===- ParentMapContext.h - Map of parents using DynTypedNode -------*- C++ -*-===//
//===- ParentMapContext.h - Map of parents using DynTypedNode ---*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
Expand Down
25 changes: 21 additions & 4 deletions clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,36 @@ class ControlFlowContext {
return BlockReachable[B.getBlockID()];
}

/// Returns whether `B` contains an expression that is consumed in a
/// different block than `B` (i.e. the parent of the expression is in a
/// different block).
/// This happens if there is control flow within a full-expression (triggered
/// by `&&`, `||`, or the conditional operator). Note that the operands of
/// these operators are not the only expressions that can be consumed in a
/// different block. For example, in the function call
/// `f(&i, cond() ? 1 : 0)`, `&i` is in a different block than the `CallExpr`.
bool containsExprConsumedInDifferentBlock(const CFGBlock &B) const {
return ContainsExprConsumedInDifferentBlock.contains(&B);
}

private:
ControlFlowContext(const Decl &D, std::unique_ptr<CFG> Cfg,
llvm::DenseMap<const Stmt *, const CFGBlock *> StmtToBlock,
llvm::BitVector BlockReachable)
ControlFlowContext(
const Decl &D, std::unique_ptr<CFG> Cfg,
llvm::DenseMap<const Stmt *, const CFGBlock *> StmtToBlock,
llvm::BitVector BlockReachable,
llvm::DenseSet<const CFGBlock *> ContainsExprConsumedInDifferentBlock)
: ContainingDecl(D), Cfg(std::move(Cfg)),
StmtToBlock(std::move(StmtToBlock)),
BlockReachable(std::move(BlockReachable)) {}
BlockReachable(std::move(BlockReachable)),
ContainsExprConsumedInDifferentBlock(
std::move(ContainsExprConsumedInDifferentBlock)) {}

/// The `Decl` containing the statement used to construct the CFG.
const Decl &ContainingDecl;
std::unique_ptr<CFG> Cfg;
llvm::DenseMap<const Stmt *, const CFGBlock *> StmtToBlock;
llvm::BitVector BlockReachable;
llvm::DenseSet<const CFGBlock *> ContainsExprConsumedInDifferentBlock;
};

} // namespace dataflow
Expand Down
11 changes: 10 additions & 1 deletion clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,14 @@ class Environment {
bool equivalentTo(const Environment &Other,
Environment::ValueModel &Model) const;

/// How to treat expression state (`ExprToLoc` and `ExprToVal`) in a join.
/// If the join happens within a full expression, expression state should be
/// kept; otherwise, we can discard it.
enum ExprJoinBehavior {
DiscardExprState,
KeepExprState,
};

/// Joins two environments by taking the intersection of storage locations and
/// values that are stored in them. Distinct values that are assigned to the
/// same storage locations in `EnvA` and `EnvB` are merged using `Model`.
Expand All @@ -218,7 +226,8 @@ class Environment {
///
/// `EnvA` and `EnvB` must use the same `DataflowAnalysisContext`.
static Environment join(const Environment &EnvA, const Environment &EnvB,
Environment::ValueModel &Model);
Environment::ValueModel &Model,
ExprJoinBehavior ExprBehavior);

/// Widens the environment point-wise, using `PrevEnv` as needed to inform the
/// approximation.
Expand Down
18 changes: 18 additions & 0 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -4542,6 +4542,12 @@ def GetDeviceSideMangledName : LangBuiltin<"CUDA_LANG"> {
}

// HLSL
def HLSLAny : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_elementwise_any"];
let Attributes = [NoThrow, Const];
let Prototype = "bool(...)";
}

def HLSLWaveActiveCountBits : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_wave_active_count_bits"];
let Attributes = [NoThrow, Const];
Expand Down Expand Up @@ -4572,6 +4578,18 @@ def HLSLLerp : LangBuiltin<"HLSL_LANG"> {
let Prototype = "void(...)";
}

def HLSLMad : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_mad"];
let Attributes = [NoThrow, Const];
let Prototype = "void(...)";
}

def HLSLRcp : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_elementwise_rcp"];
let Attributes = [NoThrow, Const];
let Prototype = "void(...)";
}

// Builtins for XRay.
def XRayCustomEvent : Builtin {
let Spellings = ["__xray_customevent"];
Expand Down
11 changes: 7 additions & 4 deletions clang/include/clang/Basic/BuiltinsAMDGPU.def
Original file line number Diff line number Diff line change
Expand Up @@ -256,10 +256,10 @@ TARGET_BUILTIN(__builtin_amdgcn_sudot4, "iIbiIbiiIb", "nc", "dot8-insts")
TARGET_BUILTIN(__builtin_amdgcn_sdot8, "SiSiSiSiIb", "nc", "dot1-insts")
TARGET_BUILTIN(__builtin_amdgcn_udot8, "UiUiUiUiIb", "nc", "dot7-insts")
TARGET_BUILTIN(__builtin_amdgcn_sudot8, "iIbiIbiiIb", "nc", "dot8-insts")
TARGET_BUILTIN(__builtin_amdgcn_dot4_f32_fp8_bf8, "fUiUif", "nc", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_dot4_f32_bf8_fp8, "fUiUif", "nc", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_dot4_f32_fp8_fp8, "fUiUif", "nc", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_dot4_f32_bf8_bf8, "fUiUif", "nc", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_dot4_f32_fp8_bf8, "fUiUif", "nc", "dot11-insts")
TARGET_BUILTIN(__builtin_amdgcn_dot4_f32_bf8_fp8, "fUiUif", "nc", "dot11-insts")
TARGET_BUILTIN(__builtin_amdgcn_dot4_f32_fp8_fp8, "fUiUif", "nc", "dot11-insts")
TARGET_BUILTIN(__builtin_amdgcn_dot4_f32_bf8_bf8, "fUiUif", "nc", "dot11-insts")

//===----------------------------------------------------------------------===//
// GFX10+ only builtins.
Expand Down Expand Up @@ -325,6 +325,9 @@ BUILTIN(__builtin_amdgcn_read_exec_hi, "Ui", "nc")

BUILTIN(__builtin_amdgcn_endpgm, "v", "nr")

BUILTIN(__builtin_amdgcn_get_fpenv, "WUi", "n")
BUILTIN(__builtin_amdgcn_set_fpenv, "vWUi", "n")

//===----------------------------------------------------------------------===//
// R600-NI only builtins.
//===----------------------------------------------------------------------===//
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/DeclNodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def LinkageSpec : DeclNode<Decl>, DeclContext;
def Export : DeclNode<Decl>, DeclContext;
def ObjCPropertyImpl : DeclNode<Decl>;
def FileScopeAsm : DeclNode<Decl>;
def TopLevelStmt : DeclNode<Decl>;
def TopLevelStmt : DeclNode<Decl>, DeclContext;
def AccessSpec : DeclNode<Decl>;
def Friend : DeclNode<Decl>;
def FriendTemplate : DeclNode<Decl>;
Expand Down
10 changes: 9 additions & 1 deletion clang/include/clang/Basic/DiagnosticGroups.td
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,15 @@ def MethodSignatures : DiagGroup<"method-signatures">;
def MismatchedParameterTypes : DiagGroup<"mismatched-parameter-types">;
def MismatchedReturnTypes : DiagGroup<"mismatched-return-types">;
def MismatchedTags : DiagGroup<"mismatched-tags">;
def MissingFieldInitializers : DiagGroup<"missing-field-initializers">;
def MissingDesignatedFieldInitializers : DiagGroup<"missing-designated-field-initializers">{
code Documentation = [{
Warn about designated initializers with some fields missing (only in C++).
}];
}
// Default -Wmissing-field-initializers matches gcc behavior,
// but missing-designated-field-initializers can be turned off to match old clang behavior.
def MissingFieldInitializers : DiagGroup<"missing-field-initializers",
[MissingDesignatedFieldInitializers]>;
def ModuleLock : DiagGroup<"module-lock">;
def ModuleBuild : DiagGroup<"module-build">;
def ModuleImport : DiagGroup<"module-import">;
Expand Down
46 changes: 26 additions & 20 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -2946,6 +2946,18 @@ def warn_private_extern : Warning<
def note_private_extern : Note<
"use __attribute__((visibility(\"hidden\"))) attribute instead">;

// C23 constexpr
def err_c23_constexpr_not_variable : Error<
"'constexpr' can only be used in variable declarations">;
def err_c23_constexpr_invalid_type : Error<
"constexpr variable cannot have type %0">;
def err_c23_constexpr_init_not_representable : Error<
"constexpr initializer evaluates to %0 which is not exactly representable in type %1">;
def err_c23_constexpr_init_type_mismatch : Error<
"constexpr initializer for type %0 is of type %1">;
def err_c23_constexpr_pointer_not_null : Error<
"constexpr pointer initializer is not null">;

// C++ Concepts
def err_concept_decls_may_only_appear_in_global_namespace_scope : Error<
"concept declarations may only appear in global or namespace scope">;
Expand Down Expand Up @@ -6170,6 +6182,10 @@ def ext_initializer_string_for_char_array_too_long : ExtWarn<
def warn_missing_field_initializers : Warning<
"missing field %0 initializer">,
InGroup<MissingFieldInitializers>, DefaultIgnore;
// The same warning, but another group is needed to disable it separately.
def warn_missing_designated_field_initializers : Warning<
warn_missing_field_initializers.Summary>,
InGroup<MissingDesignatedFieldInitializers>, DefaultIgnore;
def warn_braces_around_init : Warning<
"braces around %select{scalar |}0initializer">,
InGroup<DiagGroup<"braced-scalar-init">>;
Expand Down Expand Up @@ -9591,13 +9607,10 @@ def err_defaulted_copy_assign_not_ref : Error<
"the parameter for an explicitly-defaulted copy assignment operator must be an "
"lvalue reference type">;
def err_incorrect_defaulted_constexpr : Error<
"defaulted definition of %sub{select_special_member_kind}0 "
"is not constexpr">;
"defaulted definition of %sub{select_special_member_kind}0 cannot be marked %select{constexpr|consteval}1 "
"before C++23">;
def err_incorrect_defaulted_constexpr_with_vb: Error<
"%sub{select_special_member_kind}0 cannot be 'constexpr' in a class with virtual base class">;
def err_incorrect_defaulted_consteval : Error<
"defaulted declaration of %sub{select_special_member_kind}0 "
"cannot be consteval because implicit definition is not constexpr">;
def warn_defaulted_method_deleted : Warning<
"explicitly defaulted %sub{select_special_member_kind}0 is implicitly "
"deleted">, InGroup<DefaultedFunctionDeleted>;
Expand Down Expand Up @@ -9708,21 +9721,12 @@ def note_defaulted_comparison_cannot_deduce_undeduced_auto : Note<
"%select{|member|base class}0 %1 declared here">;
def note_defaulted_comparison_cannot_deduce_callee : Note<
"selected 'operator<=>' for %select{|member|base class}0 %1 declared here">;
def ext_defaulted_comparison_constexpr_mismatch : Extension<
"defaulted definition of %select{%sub{select_defaulted_comparison_kind}1|"
"three-way comparison operator}0 that is "
"declared %select{constexpr|consteval}2 but"
"%select{|for which the corresponding implicit 'operator==' }0 "
"invokes a non-constexpr comparison function is a C++23 extension">,
InGroup<DiagGroup<"c++23-default-comp-relaxed-constexpr">>;
def warn_cxx23_compat_defaulted_comparison_constexpr_mismatch : Warning<
def err_defaulted_comparison_constexpr_mismatch : Error<
"defaulted definition of %select{%sub{select_defaulted_comparison_kind}1|"
"three-way comparison operator}0 that is "
"declared %select{constexpr|consteval}2 but"
"%select{|for which the corresponding implicit 'operator==' }0 "
"invokes a non-constexpr comparison function is incompatible with C++ "
"standards before C++23">,
InGroup<CXXPre23Compat>, DefaultIgnore;
"three-way comparison operator}0 cannot be "
"declared %select{constexpr|consteval}2 because "
"%select{it|for which the corresponding implicit 'operator==' }0 "
"invokes a non-constexpr comparison function ">;
def note_defaulted_comparison_not_constexpr : Note<
"non-constexpr comparison function would be used to compare "
"%select{|member %1|base class %1}0">;
Expand Down Expand Up @@ -9901,7 +9905,7 @@ def err_lifetimebound_ctor_dtor : Error<
// CHECK: returning address/reference of stack memory
def warn_ret_stack_addr_ref : Warning<
"%select{address of|reference to}0 stack memory associated with "
"%select{local variable|parameter}2 %1 returned">,
"%select{local variable|parameter|compound literal}2 %1 returned">,
InGroup<ReturnStackAddress>;
def warn_ret_local_temp_addr_ref : Warning<
"returning %select{address of|reference to}0 local temporary object">,
Expand Down Expand Up @@ -11336,6 +11340,8 @@ def err_omp_device_type_mismatch : Error<
def err_omp_wrong_device_function_call : Error<
"function with 'device_type(%0)' is not available on %select{device|host}1">;
def note_omp_marked_device_type_here : Note<"marked as 'device_type(%0)' here">;
def err_omp_declare_target_has_local_vars : Error<
"local variable '%0' should not be used in 'declare target' directive; ">;
def warn_omp_declare_target_after_first_use : Warning<
"declaration marked as declare target after first use, it may lead to incorrect results">,
InGroup<OpenMPTarget>;
Expand Down
11 changes: 5 additions & 6 deletions clang/include/clang/Basic/Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,11 @@ class alignas(8) Module {
Kind == ModulePartitionImplementation;
}

/// Is this a module partition implementation unit.
bool isModulePartitionImplementation() const {
return Kind == ModulePartitionImplementation;
}

/// Is this a module implementation.
bool isModuleImplementation() const {
return Kind == ModuleImplementationUnit;
Expand Down Expand Up @@ -853,12 +858,6 @@ class VisibleModuleSet {
VisibleCallback Vis = [](Module *) {},
ConflictCallback Cb = [](ArrayRef<Module *>, Module *,
StringRef) {});

/// Make transitive imports visible for [module.import]/7.
void makeTransitiveImportsVisible(
Module *M, SourceLocation Loc, VisibleCallback Vis = [](Module *) {},
ConflictCallback Cb = [](ArrayRef<Module *>, Module *, StringRef) {});

private:
/// Import locations for each visible module. Indexed by the module's
/// VisibilityID.
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/OpenCLExtensionTypes.def
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//===-- OpenCLExtensionTypes.def - Metadata about BuiltinTypes ------*- C++ -*-===//
//===-- OpenCLExtensionTypes.def - Metadata about BuiltinTypes --*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
Expand Down
8 changes: 4 additions & 4 deletions clang/include/clang/Basic/RISCVVTypes.def
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ RVV_VECTOR_TYPE_INT("__rvv_uint64m2x4_t", RvvUint64m2x4, RvvUint64m2x4Ty, 2, 64,

RVV_VECTOR_TYPE_INT("__rvv_uint64m4x2_t", RvvUint64m4x2, RvvUint64m4x2Ty, 4, 64, 2, false)

//===- Float16 tuple types --------------------------------------------------===//
//===- Float16 tuple types ------------------------------------------------===//
RVV_VECTOR_TYPE_FLOAT("__rvv_float16mf4x2_t", RvvFloat16mf4x2, RvvFloat16mf4x2Ty, 1, 16, 2)
RVV_VECTOR_TYPE_FLOAT("__rvv_float16mf4x3_t", RvvFloat16mf4x3, RvvFloat16mf4x3Ty, 1, 16, 3)
RVV_VECTOR_TYPE_FLOAT("__rvv_float16mf4x4_t", RvvFloat16mf4x4, RvvFloat16mf4x4Ty, 1, 16, 4)
Expand Down Expand Up @@ -414,7 +414,7 @@ RVV_VECTOR_TYPE_FLOAT("__rvv_float16m2x4_t", RvvFloat16m2x4, RvvFloat16m2x4Ty, 8

RVV_VECTOR_TYPE_FLOAT("__rvv_float16m4x2_t", RvvFloat16m4x2, RvvFloat16m4x2Ty, 16, 16, 2)

//===- Float32 tuple types --------------------------------------------------===//
//===- Float32 tuple types ------------------------------------------------===//
RVV_VECTOR_TYPE_FLOAT("__rvv_float32mf2x2_t", RvvFloat32mf2x2, RvvFloat32mf2x2Ty, 1, 32, 2)
RVV_VECTOR_TYPE_FLOAT("__rvv_float32mf2x3_t", RvvFloat32mf2x3, RvvFloat32mf2x3Ty, 1, 32, 3)
RVV_VECTOR_TYPE_FLOAT("__rvv_float32mf2x4_t", RvvFloat32mf2x4, RvvFloat32mf2x4Ty, 1, 32, 4)
Expand All @@ -437,7 +437,7 @@ RVV_VECTOR_TYPE_FLOAT("__rvv_float32m2x4_t", RvvFloat32m2x4, RvvFloat32m2x4Ty, 4

RVV_VECTOR_TYPE_FLOAT("__rvv_float32m4x2_t", RvvFloat32m4x2, RvvFloat32m4x2Ty, 8, 32, 2)

//===- Float64 tuple types -------------------------------------------------===//
//===- Float64 tuple types ------------------------------------------------===//
RVV_VECTOR_TYPE_FLOAT("__rvv_float64m1x2_t", RvvFloat64m1x2, RvvFloat64m1x2Ty, 1, 64, 2)
RVV_VECTOR_TYPE_FLOAT("__rvv_float64m1x3_t", RvvFloat64m1x3, RvvFloat64m1x3Ty, 1, 64, 3)
RVV_VECTOR_TYPE_FLOAT("__rvv_float64m1x4_t", RvvFloat64m1x4, RvvFloat64m1x4Ty, 1, 64, 4)
Expand All @@ -452,7 +452,7 @@ RVV_VECTOR_TYPE_FLOAT("__rvv_float64m2x4_t", RvvFloat64m2x4, RvvFloat64m2x4Ty, 2

RVV_VECTOR_TYPE_FLOAT("__rvv_float64m4x2_t", RvvFloat64m4x2, RvvFloat64m4x2Ty, 4, 64, 2)

//===- BFloat16 tuple types -------------------------------------------------===//
//===- BFloat16 tuple types -----------------------------------------------===//
RVV_VECTOR_TYPE_BFLOAT("__rvv_bfloat16mf4x2_t", RvvBFloat16mf4x2, RvvBFloat16mf4x2Ty,
1, 16, 2)
RVV_VECTOR_TYPE_BFLOAT("__rvv_bfloat16mf4x3_t", RvvBFloat16mf4x3, RvvBFloat16mf4x3Ty,
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/TokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ CXX11_KEYWORD(alignas , KEYC23)
CXX11_UNARY_EXPR_OR_TYPE_TRAIT(alignof, AlignOf, KEYC23)
CXX11_KEYWORD(char16_t , KEYNOMS18)
CXX11_KEYWORD(char32_t , KEYNOMS18)
CXX11_KEYWORD(constexpr , 0)
CXX11_KEYWORD(constexpr , KEYC23)
CXX11_KEYWORD(decltype , 0)
CXX11_KEYWORD(noexcept , 0)
CXX11_KEYWORD(nullptr , KEYC23)
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/arm_neon_incl.td
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//===--- arm_neon_incl.td - ARM NEON compiler interface ------------------------===//
//===--- arm_neon_incl.td - ARM NEON compiler interface -------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
Expand Down
23,076 changes: 11,664 additions & 11,412 deletions clang/include/clang/Sema/Sema.h

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion clang/include/clang/Serialization/PCHContainerOperations.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//===--- Serialization/PCHContainerOperations.h - PCH Containers --*- C++ -*-===//
//===-- PCHContainerOperations.h - PCH Containers ---------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
Original file line number Diff line number Diff line change
Expand Up @@ -1654,6 +1654,10 @@ def StdCLibraryFunctionsTesterChecker : Checker<"StdCLibraryFunctionsTester">,
WeakDependencies<[StdCLibraryFunctionsChecker]>,
Documentation<NotDocumented>;

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

} // end "debug"


Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//===--- PathDiagnosticConsumers.h - Path Diagnostic Clients ------*- C++ -*-===//
//===--- PathDiagnosticConsumers.h - Path Diagnostic Clients ----*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CHECKERHELPERS_H
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CHECKERHELPERS_H

#include "ProgramState_Fwd.h"
#include "SVals.h"

#include "clang/AST/OperationKinds.h"
#include "clang/AST/Stmt.h"
#include "clang/Basic/OperatorKinds.h"
Expand Down Expand Up @@ -110,6 +113,9 @@ class OperatorKind {
OperatorKind operationKindFromOverloadedOperator(OverloadedOperatorKind OOK,
bool IsBinary);

std::optional<DefinedSVal> getPointeeDefVal(SVal PtrSVal,
ProgramStateRef State);

} // namespace ento

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

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

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

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

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

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/ARCMigrate/TransGCAttrs.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//===--- TransGCAttrs.cpp - Transformations to ARC mode --------------------===//
//===--- TransGCAttrs.cpp - Transformations to ARC mode -------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
Expand Down
36 changes: 24 additions & 12 deletions clang/lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2465,7 +2465,7 @@ bool VarDecl::mightBeUsableInConstantExpressions(const ASTContext &C) const {

// OpenCL permits const integral variables to be used in constant
// expressions, like in C++98.
if (!Lang.CPlusPlus && !Lang.OpenCL)
if (!Lang.CPlusPlus && !Lang.OpenCL && !Lang.C23)
return false;

// Function parameters are never usable in constant expressions.
Expand All @@ -2487,14 +2487,19 @@ bool VarDecl::mightBeUsableInConstantExpressions(const ASTContext &C) const {
if (!getType().isConstant(C) || getType().isVolatileQualified())
return false;

// In C++, const, non-volatile variables of integral or enumeration types
// can be used in constant expressions.
if (getType()->isIntegralOrEnumerationType())
// In C++, but not in C, const, non-volatile variables of integral or
// enumeration types can be used in constant expressions.
if (getType()->isIntegralOrEnumerationType() && !Lang.C23)
return true;

// C23 6.6p7: An identifier that is:
// ...
// - declared with storage-class specifier constexpr and has an object type,
// is a named constant, ... such a named constant is a constant expression
// with the type and value of the declared object.
// Additionally, in C++11, non-volatile constexpr variables can be used in
// constant expressions.
return Lang.CPlusPlus11 && isConstexpr();
return (Lang.CPlusPlus11 || Lang.C23) && isConstexpr();
}

bool VarDecl::isUsableInConstantExpressions(const ASTContext &Context) const {
Expand Down Expand Up @@ -2572,11 +2577,11 @@ APValue *VarDecl::evaluateValueImpl(SmallVectorImpl<PartialDiagnosticAt> &Notes,
bool Result = Init->EvaluateAsInitializer(Eval->Evaluated, Ctx, this, Notes,
IsConstantInitialization);

// In C++, this isn't a constant initializer if we produced notes. In that
// In C++/C23, this isn't a constant initializer if we produced notes. In that
// case, we can't keep the result, because it may only be correct under the
// assumption that the initializer is a constant context.
if (IsConstantInitialization && Ctx.getLangOpts().CPlusPlus &&
!Notes.empty())
if (IsConstantInitialization &&
(Ctx.getLangOpts().CPlusPlus || Ctx.getLangOpts().C23) && !Notes.empty())
Result = false;

// Ensure the computed APValue is cleaned up later if evaluation succeeded,
Expand Down Expand Up @@ -2634,7 +2639,9 @@ bool VarDecl::checkForConstantInitialization(
// std::is_constant_evaluated()).
assert(!Eval->WasEvaluated &&
"already evaluated var value before checking for constant init");
assert(getASTContext().getLangOpts().CPlusPlus && "only meaningful in C++");
assert((getASTContext().getLangOpts().CPlusPlus ||
getASTContext().getLangOpts().C23) &&
"only meaningful in C++/C23");

assert(!getInit()->isValueDependent());

Expand Down Expand Up @@ -5545,14 +5552,13 @@ FileScopeAsmDecl *FileScopeAsmDecl::CreateDeserialized(ASTContext &C,
void TopLevelStmtDecl::anchor() {}

TopLevelStmtDecl *TopLevelStmtDecl::Create(ASTContext &C, Stmt *Statement) {
assert(Statement);
assert(C.getLangOpts().IncrementalExtensions &&
"Must be used only in incremental mode");

SourceLocation BeginLoc = Statement->getBeginLoc();
SourceLocation Loc = Statement ? Statement->getBeginLoc() : SourceLocation();
DeclContext *DC = C.getTranslationUnitDecl();

return new (C, DC) TopLevelStmtDecl(DC, BeginLoc, Statement);
return new (C, DC) TopLevelStmtDecl(DC, Loc, Statement);
}

TopLevelStmtDecl *TopLevelStmtDecl::CreateDeserialized(ASTContext &C,
Expand All @@ -5565,6 +5571,12 @@ SourceRange TopLevelStmtDecl::getSourceRange() const {
return SourceRange(getLocation(), Statement->getEndLoc());
}

void TopLevelStmtDecl::setStmt(Stmt *S) {
assert(S);
Statement = S;
setLocation(Statement->getBeginLoc());
}

void EmptyDecl::anchor() {}

EmptyDecl *EmptyDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) {
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/DeclBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1352,6 +1352,7 @@ DeclContext *DeclContext::getPrimaryContext() {
case Decl::ExternCContext:
case Decl::LinkageSpec:
case Decl::Export:
case Decl::TopLevelStmt:
case Decl::Block:
case Decl::Captured:
case Decl::OMPDeclareReduction:
Expand Down
13 changes: 8 additions & 5 deletions clang/lib/AST/DeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -400,10 +400,11 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,

// C++11 [class.ctor]p6:
// If that user-written default constructor would satisfy the
// requirements of a constexpr constructor, the implicitly-defined
// default constructor is constexpr.
// requirements of a constexpr constructor/function(C++23), the
// implicitly-defined default constructor is constexpr.
if (!BaseClassDecl->hasConstexprDefaultConstructor())
data().DefaultedDefaultConstructorIsConstexpr = false;
data().DefaultedDefaultConstructorIsConstexpr =
C.getLangOpts().CPlusPlus23;

// C++1z [class.copy]p8:
// The implicitly-declared copy constructor for a class X will have
Expand Down Expand Up @@ -548,7 +549,8 @@ void CXXRecordDecl::addedClassSubobject(CXXRecordDecl *Subobj) {
// -- for every subobject of class type or (possibly multi-dimensional)
// array thereof, that class type shall have a constexpr destructor
if (!Subobj->hasConstexprDestructor())
data().DefaultedDestructorIsConstexpr = false;
data().DefaultedDestructorIsConstexpr =
getASTContext().getLangOpts().CPlusPlus23;

// C++20 [temp.param]p7:
// A structural type is [...] a literal class type [for which] the types
Expand Down Expand Up @@ -1297,7 +1299,8 @@ void CXXRecordDecl::addedMember(Decl *D) {
!FieldRec->hasConstexprDefaultConstructor() && !isUnion())
// The standard requires any in-class initializer to be a constant
// expression. We consider this to be a defect.
data().DefaultedDefaultConstructorIsConstexpr = false;
data().DefaultedDefaultConstructorIsConstexpr =
Context.getLangOpts().CPlusPlus23;

// C++11 [class.copy]p8:
// The implicitly-declared copy constructor for a class X will have
Expand Down
18 changes: 15 additions & 3 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2778,7 +2778,9 @@ static bool CheckedIntArithmetic(EvalInfo &Info, const Expr *E,
if (Info.checkingForUndefinedBehavior())
Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
diag::warn_integer_constant_overflow)
<< toString(Result, 10) << E->getType() << E->getSourceRange();
<< toString(Result, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
/*UpperCase=*/true, /*InsertSeparators=*/true)
<< E->getType() << E->getSourceRange();
return HandleOverflow(Info, E, Value, E->getType());
}
return true;
Expand Down Expand Up @@ -4131,6 +4133,10 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
}

bool IsConstant = BaseType.isConstant(Info.Ctx);
bool ConstexprVar = false;
if (const auto *VD = dyn_cast_if_present<VarDecl>(
Info.EvaluatingDecl.dyn_cast<const ValueDecl *>()))
ConstexprVar = VD->isConstexpr();

// Unless we're looking at a local variable or argument in a constexpr call,
// the variable we're reading must be const.
Expand All @@ -4150,6 +4156,9 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
return CompleteObject();
} else if (VD->isConstexpr()) {
// OK, we can read this variable.
} else if (Info.getLangOpts().C23 && ConstexprVar) {
Info.FFDiag(E);
return CompleteObject();
} else if (BaseType->isIntegralOrEnumerationType()) {
if (!IsConstant) {
if (!IsAccess)
Expand Down Expand Up @@ -13910,7 +13919,9 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
if (Info.checkingForUndefinedBehavior())
Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
diag::warn_integer_constant_overflow)
<< toString(Value, 10) << E->getType() << E->getSourceRange();
<< toString(Value, 10, Value.isSigned(), /*formatAsCLiteral=*/false,
/*UpperCase=*/true, /*InsertSeparators=*/true)
<< E->getType() << E->getSourceRange();

if (!HandleOverflow(Info, E, -Value.extend(Value.getBitWidth() + 1),
E->getType()))
Expand Down Expand Up @@ -15822,7 +15833,8 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
EStatus.Diag = &Notes;

EvalInfo Info(Ctx, EStatus,
(IsConstantInitialization && Ctx.getLangOpts().CPlusPlus)
(IsConstantInitialization &&
(Ctx.getLangOpts().CPlusPlus || Ctx.getLangOpts().C23))
? EvalInfo::EM_ConstantExpression
: EvalInfo::EM_ConstantFold);
Info.setEvaluatingDecl(VD, Value);
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/ByteCodeEmitter.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//===--- ByteCodeEmitter.h - Instruction emitter for the VM ---------*- C++ -*-===//
//===--- ByteCodeEmitter.h - Instruction emitter for the VM -----*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
Expand Down
166 changes: 125 additions & 41 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -314,11 +314,7 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
for (unsigned I = 0; I != 2; ++I) {
if (!this->emitGetLocal(PT_Ptr, *SubExprOffset, CE))
return false;
if (!this->emitConstUint8(I, CE))
return false;
if (!this->emitArrayElemPtrPopUint8(CE))
return false;
if (!this->emitLoadPop(SourceElemT, CE))
if (!this->emitArrayElemPop(SourceElemT, I, CE))
return false;

// Do the cast.
Expand Down Expand Up @@ -393,12 +389,16 @@ bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {
if (BO->isLogicalOp())
return this->VisitLogicalBinOp(BO);

if (BO->getType()->isAnyComplexType())
return this->VisitComplexBinOp(BO);

const Expr *LHS = BO->getLHS();
const Expr *RHS = BO->getRHS();

if (BO->getType()->isAnyComplexType())
return this->VisitComplexBinOp(BO);
if ((LHS->getType()->isAnyComplexType() ||
RHS->getType()->isAnyComplexType()) &&
BO->isComparisonOp())
return this->emitComplexComparison(LHS, RHS, BO);

if (BO->isPtrMemOp())
return this->visit(RHS);

Expand Down Expand Up @@ -725,11 +725,8 @@ bool ByteCodeExprGen<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
if (IsComplex) {
if (!this->emitGetLocal(PT_Ptr, Offset, E))
return false;
if (!this->emitConstUint8(ElemIndex, E))
return false;
if (!this->emitArrayElemPtrPopUint8(E))
return false;
return this->emitLoadPop(classifyComplexElementType(E->getType()), E);
return this->emitArrayElemPop(classifyComplexElementType(E->getType()),
ElemIndex, E);
}
if (ElemIndex == 0)
return this->emitGetLocal(classifyPrim(E->getType()), Offset, E);
Expand Down Expand Up @@ -1649,7 +1646,8 @@ bool ByteCodeExprGen<Emitter>::VisitMaterializeTemporaryExpr(
SubExpr, *SubExprT, /*IsConst=*/true, /*IsExtended=*/true)) {
if (!this->visit(SubExpr))
return false;
this->emitSetLocal(*SubExprT, *LocalIndex, E);
if (!this->emitSetLocal(*SubExprT, *LocalIndex, E))
return false;
return this->emitGetPtrLocal(*LocalIndex, E);
}
} else {
Expand Down Expand Up @@ -3123,16 +3121,16 @@ bool ByteCodeExprGen<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {

if (!this->visit(SubExpr))
return false;
if (!this->emitConstUint8(1, E))
return false;
if (!this->emitArrayElemPtrPopUint8(E))
return false;

if (SubExpr->isLValue()) {
if (!this->emitConstUint8(1, E))
return false;
return this->emitArrayElemPtrPopUint8(E);
}

// Since our _Complex implementation does not map to a primitive type,
// we sometimes have to do the lvalue-to-rvalue conversion here manually.
if (!SubExpr->isLValue())
return this->emitLoadPop(classifyPrim(E->getType()), E);
return true;
return this->emitArrayElemPop(classifyPrim(E->getType()), 1, E);
}
case UO_Extension:
return this->delegate(SubExpr);
Expand Down Expand Up @@ -3343,17 +3341,15 @@ bool ByteCodeExprGen<Emitter>::emitComplexReal(const Expr *SubExpr) {

if (!this->visit(SubExpr))
return false;
if (!this->emitConstUint8(0, SubExpr))
return false;
if (!this->emitArrayElemPtrPopUint8(SubExpr))
return false;
if (SubExpr->isLValue()) {
if (!this->emitConstUint8(0, SubExpr))
return false;
return this->emitArrayElemPtrPopUint8(SubExpr);
}

// Since our _Complex implementation does not map to a primitive type,
// we sometimes have to do the lvalue-to-rvalue conversion here manually.
if (!SubExpr->isLValue())
return this->emitLoadPop(classifyComplexElementType(SubExpr->getType()),
SubExpr);
return true;
// Rvalue, load the actual element.
return this->emitArrayElemPop(classifyComplexElementType(SubExpr->getType()),
0, SubExpr);
}

template <class Emitter>
Expand All @@ -3362,11 +3358,7 @@ bool ByteCodeExprGen<Emitter>::emitComplexBoolCast(const Expr *E) {
PrimType ElemT = classifyComplexElementType(E->getType());
// We emit the expression (__real(E) != 0 || __imag(E) != 0)
// for us, that means (bool)E[0] || (bool)E[1]
if (!this->emitConstUint8(0, E))
return false;
if (!this->emitArrayElemPtrUint8(E))
return false;
if (!this->emitLoadPop(ElemT, E))
if (!this->emitArrayElem(ElemT, 0, E))
return false;
if (ElemT == PT_Float) {
if (!this->emitCastFloatingIntegral(PT_Bool, E))
Expand All @@ -3381,11 +3373,7 @@ bool ByteCodeExprGen<Emitter>::emitComplexBoolCast(const Expr *E) {
if (!this->jumpTrue(LabelTrue))
return false;

if (!this->emitConstUint8(1, E))
return false;
if (!this->emitArrayElemPtrPopUint8(E))
return false;
if (!this->emitLoadPop(ElemT, E))
if (!this->emitArrayElemPop(ElemT, 1, E))
return false;
if (ElemT == PT_Float) {
if (!this->emitCastFloatingIntegral(PT_Bool, E))
Expand All @@ -3410,6 +3398,102 @@ bool ByteCodeExprGen<Emitter>::emitComplexBoolCast(const Expr *E) {
return true;
}

template <class Emitter>
bool ByteCodeExprGen<Emitter>::emitComplexComparison(const Expr *LHS,
const Expr *RHS,
const BinaryOperator *E) {
assert(E->isComparisonOp());
assert(!Initializing);
assert(!DiscardResult);

PrimType ElemT;
bool LHSIsComplex;
unsigned LHSOffset;
if (LHS->getType()->isAnyComplexType()) {
LHSIsComplex = true;
ElemT = classifyComplexElementType(LHS->getType());
LHSOffset = allocateLocalPrimitive(LHS, PT_Ptr, /*IsConst=*/true,
/*IsExtended=*/false);
if (!this->visit(LHS))
return false;
if (!this->emitSetLocal(PT_Ptr, LHSOffset, E))
return false;
} else {
LHSIsComplex = false;
PrimType LHST = classifyPrim(LHS->getType());
LHSOffset = this->allocateLocalPrimitive(LHS, LHST, true, false);
if (!this->visit(LHS))
return false;
if (!this->emitSetLocal(LHST, LHSOffset, E))
return false;
}

bool RHSIsComplex;
unsigned RHSOffset;
if (RHS->getType()->isAnyComplexType()) {
RHSIsComplex = true;
ElemT = classifyComplexElementType(RHS->getType());
RHSOffset = allocateLocalPrimitive(RHS, PT_Ptr, /*IsConst=*/true,
/*IsExtended=*/false);
if (!this->visit(RHS))
return false;
if (!this->emitSetLocal(PT_Ptr, RHSOffset, E))
return false;
} else {
RHSIsComplex = false;
PrimType RHST = classifyPrim(RHS->getType());
RHSOffset = this->allocateLocalPrimitive(RHS, RHST, true, false);
if (!this->visit(RHS))
return false;
if (!this->emitSetLocal(RHST, RHSOffset, E))
return false;
}

auto getElem = [&](unsigned LocalOffset, unsigned Index,
bool IsComplex) -> bool {
if (IsComplex) {
if (!this->emitGetLocal(PT_Ptr, LocalOffset, E))
return false;
return this->emitArrayElemPop(ElemT, Index, E);
}
return this->emitGetLocal(ElemT, LocalOffset, E);
};

for (unsigned I = 0; I != 2; ++I) {
// Get both values.
if (!getElem(LHSOffset, I, LHSIsComplex))
return false;
if (!getElem(RHSOffset, I, RHSIsComplex))
return false;
// And compare them.
if (!this->emitEQ(ElemT, E))
return false;

if (!this->emitCastBoolUint8(E))
return false;
}

// We now have two bool values on the stack. Compare those.
if (!this->emitAddUint8(E))
return false;
if (!this->emitConstUint8(2, E))
return false;

if (E->getOpcode() == BO_EQ) {
if (!this->emitEQUint8(E))
return false;
} else if (E->getOpcode() == BO_NE) {
if (!this->emitNEUint8(E))
return false;
} else
return false;

// In C, this returns an int.
if (PrimType ResT = classifyPrim(E->getType()); ResT != PT_Bool)
return this->emitCast(PT_Bool, ResT, E);
return true;
}

/// When calling this, we have a pointer of the local-to-destroy
/// on the stack.
/// Emit destruction of record types (or arrays of record types).
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/Interp/ByteCodeExprGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,8 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,

bool emitComplexReal(const Expr *SubExpr);
bool emitComplexBoolCast(const Expr *E);
bool emitComplexComparison(const Expr *LHS, const Expr *RHS,
const BinaryOperator *E);

bool emitRecordDestruction(const Record *R);
bool emitDestruction(const Descriptor *Desc);
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/FunctionPointer.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//===--- FunctionPointer.h - Types for the constexpr VM ----------*- C++ -*-===//
//===--- FunctionPointer.h - Types for the constexpr VM ---------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
Expand Down
51 changes: 41 additions & 10 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,9 @@ bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
QualType Type = E->getType();
if (S.checkingForUndefinedBehavior()) {
SmallString<32> Trunc;
Value.trunc(Result.bitWidth()).toString(Trunc, 10);
Value.trunc(Result.bitWidth())
.toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
/*UpperCase=*/true, /*InsertSeparators=*/true);
auto Loc = E->getExprLoc();
S.report(Loc, diag::warn_integer_constant_overflow)
<< Trunc << Type << E->getSourceRange();
Expand Down Expand Up @@ -499,7 +501,9 @@ bool Neg(InterpState &S, CodePtr OpPC) {

if (S.checkingForUndefinedBehavior()) {
SmallString<32> Trunc;
NegatedValue.trunc(Result.bitWidth()).toString(Trunc, 10);
NegatedValue.trunc(Result.bitWidth())
.toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
/*UpperCase=*/true, /*InsertSeparators=*/true);
auto Loc = E->getExprLoc();
S.report(Loc, diag::warn_integer_constant_overflow)
<< Trunc << Type << E->getSourceRange();
Expand All @@ -521,8 +525,7 @@ enum class IncDecOp {

template <typename T, IncDecOp Op, PushVal DoPush>
bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
if (Ptr.isDummy())
return false;
assert(!Ptr.isDummy());

if constexpr (std::is_same_v<T, Boolean>) {
if (!S.getLangOpts().CPlusPlus14)
Expand Down Expand Up @@ -561,7 +564,9 @@ bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
QualType Type = E->getType();
if (S.checkingForUndefinedBehavior()) {
SmallString<32> Trunc;
APResult.trunc(Result.bitWidth()).toString(Trunc, 10);
APResult.trunc(Result.bitWidth())
.toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
/*UpperCase=*/true, /*InsertSeparators=*/true);
auto Loc = E->getExprLoc();
S.report(Loc, diag::warn_integer_constant_overflow)
<< Trunc << Type << E->getSourceRange();
Expand All @@ -579,7 +584,7 @@ bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool Inc(InterpState &S, CodePtr OpPC) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
if (Ptr.isDummy())
if (!CheckDummy(S, OpPC, Ptr))
return false;
if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
return false;
Expand All @@ -593,7 +598,7 @@ bool Inc(InterpState &S, CodePtr OpPC) {
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool IncPop(InterpState &S, CodePtr OpPC) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
if (Ptr.isDummy())
if (!CheckDummy(S, OpPC, Ptr))
return false;
if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
return false;
Expand All @@ -608,7 +613,7 @@ bool IncPop(InterpState &S, CodePtr OpPC) {
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool Dec(InterpState &S, CodePtr OpPC) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
if (Ptr.isDummy())
if (!CheckDummy(S, OpPC, Ptr))
return false;
if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
return false;
Expand All @@ -622,7 +627,7 @@ bool Dec(InterpState &S, CodePtr OpPC) {
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool DecPop(InterpState &S, CodePtr OpPC) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
if (Ptr.isDummy())
if (!CheckDummy(S, OpPC, Ptr))
return false;
if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
return false;
Expand Down Expand Up @@ -746,6 +751,17 @@ inline bool CmpHelperEQ<FunctionPointer>(InterpState &S, CodePtr OpPC,
CompareFn Fn) {
const auto &RHS = S.Stk.pop<FunctionPointer>();
const auto &LHS = S.Stk.pop<FunctionPointer>();

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

S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS))));
return true;
}
Expand Down Expand Up @@ -1207,7 +1223,8 @@ inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
const Pointer &Ptr = S.Stk.pop<Pointer>();

if (S.inConstantContext() && !CheckNull(S, OpPC, Ptr, CSK_Field))
if (S.getLangOpts().CPlusPlus && S.inConstantContext() &&
!CheckNull(S, OpPC, Ptr, CSK_Field))
return false;

if (CheckDummy(S, OpPC, Ptr)) {
Expand Down Expand Up @@ -1942,10 +1959,24 @@ inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
return NarrowPtr(S, OpPC);
}

template <PrimType Name, class T = typename PrimConv<Name>::T>
inline bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index) {
const Pointer &Ptr = S.Stk.peek<Pointer>();

if (!CheckLoad(S, OpPC, Ptr))
return false;

S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
return true;
}

template <PrimType Name, class T = typename PrimConv<Name>::T>
inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) {
const Pointer &Ptr = S.Stk.pop<Pointer>();

if (!CheckLoad(S, OpPC, Ptr))
return false;

S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
return true;
}
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/AST/Interp/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,14 @@ def ArrayElemPop : Opcode {
let HasGroup = 1;
}

def ArrayElem : Opcode {
let Args = [ArgUint32];
let Types = [AllTypeClass];
let HasGroup = 1;
}



//===----------------------------------------------------------------------===//
// Direct field accessors
//===----------------------------------------------------------------------===//
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/PrimType.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//===--- PrimType.h - Types for the constexpr VM --------------------*- C++ -*-===//
//===--- PrimType.h - Types for the constexpr VM ----------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
Expand Down
1 change: 0 additions & 1 deletion clang/lib/AST/Interp/Program.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ class VarDecl;

namespace interp {
class Context;
class Record;

/// The program contains and links the bytecode for all functions.
class Program final {
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/StmtOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
//
// This file implements the subclesses of Stmt class declared in StmtOpenACC.h
// This file implements the subclasses of Stmt class declared in StmtOpenACC.h
//
//===----------------------------------------------------------------------===//

Expand Down
38 changes: 37 additions & 1 deletion clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,38 @@ static llvm::BitVector findReachableBlocks(const CFG &Cfg) {
return BlockReachable;
}

static llvm::DenseSet<const CFGBlock *>
buildContainsExprConsumedInDifferentBlock(
const CFG &Cfg,
const llvm::DenseMap<const Stmt *, const CFGBlock *> &StmtToBlock) {
llvm::DenseSet<const CFGBlock *> Result;

auto CheckChildExprs = [&Result, &StmtToBlock](const Stmt *S,
const CFGBlock *Block) {
for (const Stmt *Child : S->children()) {
if (!isa<Expr>(Child))
continue;
const CFGBlock *ChildBlock = StmtToBlock.lookup(Child);
if (ChildBlock != Block)
Result.insert(ChildBlock);
}
};

for (const CFGBlock *Block : Cfg) {
if (Block == nullptr)
continue;

for (const CFGElement &Element : *Block)
if (auto S = Element.getAs<CFGStmt>())
CheckChildExprs(S->getStmt(), Block);

if (const Stmt *TerminatorCond = Block->getTerminatorCondition())
CheckChildExprs(TerminatorCond, Block);
}

return Result;
}

llvm::Expected<ControlFlowContext>
ControlFlowContext::build(const FunctionDecl &Func) {
if (!Func.doesThisDeclarationHaveABody())
Expand Down Expand Up @@ -140,8 +172,12 @@ ControlFlowContext::build(const Decl &D, Stmt &S, ASTContext &C) {

llvm::BitVector BlockReachable = findReachableBlocks(*Cfg);

llvm::DenseSet<const CFGBlock *> ContainsExprConsumedInDifferentBlock =
buildContainsExprConsumedInDifferentBlock(*Cfg, StmtToBlock);

return ControlFlowContext(D, std::move(Cfg), std::move(StmtToBlock),
std::move(BlockReachable));
std::move(BlockReachable),
std::move(ContainsExprConsumedInDifferentBlock));
}

} // namespace dataflow
Expand Down
28 changes: 24 additions & 4 deletions clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,24 @@ static llvm::DenseMap<const ValueDecl *, StorageLocation *> intersectDeclToLoc(
return Result;
}

// Performs a join on either `ExprToLoc` or `ExprToVal`.
// The maps must be consistent in the sense that any entries for the same
// expression must map to the same location / value. This is the case if we are
// performing a join for control flow within a full-expression (which is the
// only case when this function should be used).
template <typename MapT> MapT joinExprMaps(const MapT &Map1, const MapT &Map2) {
MapT Result = Map1;

for (const auto &Entry : Map2) {
[[maybe_unused]] auto [It, Inserted] = Result.insert(Entry);
// If there was an existing entry, its value should be the same as for the
// entry we were trying to insert.
assert(It->second == Entry.second);
}

return Result;
}

// Whether to consider equivalent two values with an unknown relation.
//
// FIXME: this function is a hack enabling unsoundness to support
Expand Down Expand Up @@ -627,7 +645,8 @@ LatticeJoinEffect Environment::widen(const Environment &PrevEnv,
}

Environment Environment::join(const Environment &EnvA, const Environment &EnvB,
Environment::ValueModel &Model) {
Environment::ValueModel &Model,
ExprJoinBehavior ExprBehavior) {
assert(EnvA.DACtx == EnvB.DACtx);
assert(EnvA.ThisPointeeLoc == EnvB.ThisPointeeLoc);
assert(EnvA.CallStack == EnvB.CallStack);
Expand Down Expand Up @@ -675,9 +694,10 @@ Environment Environment::join(const Environment &EnvA, const Environment &EnvB,
JoinedEnv.LocToVal =
joinLocToVal(EnvA.LocToVal, EnvB.LocToVal, EnvA, EnvB, JoinedEnv, Model);

// We intentionally leave `JoinedEnv.ExprToLoc` and `JoinedEnv.ExprToVal`
// empty, as we never need to access entries in these maps outside of the
// basic block that sets them.
if (ExprBehavior == KeepExprState) {
JoinedEnv.ExprToVal = joinExprMaps(EnvA.ExprToVal, EnvB.ExprToVal);
JoinedEnv.ExprToLoc = joinExprMaps(EnvA.ExprToLoc, EnvB.ExprToLoc);
}

return JoinedEnv;
}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,7 @@ class HTMLLogger : public Logger {
for (unsigned I = 0; I < CFG.getNumBlockIDs(); ++I) {
std::string Name = blockID(I);
// Rightwards arrow, vertical line
char ConvergenceMarker[] = u8"\\n\u2192\u007c";
const char *ConvergenceMarker = (const char *)u8"\\n\u2192\u007c";
if (BlockConverged[I])
Name += ConvergenceMarker;
GraphS << " " << blockID(I) << " [id=" << blockID(I) << " label=\""
Expand Down
32 changes: 25 additions & 7 deletions clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,18 +221,21 @@ class PrettyStackTraceCFGElement : public llvm::PrettyStackTraceEntry {
// Avoids unneccesary copies of the environment.
class JoinedStateBuilder {
AnalysisContext &AC;
Environment::ExprJoinBehavior JoinBehavior;
std::vector<const TypeErasedDataflowAnalysisState *> All;
std::deque<TypeErasedDataflowAnalysisState> Owned;

TypeErasedDataflowAnalysisState
join(const TypeErasedDataflowAnalysisState &L,
const TypeErasedDataflowAnalysisState &R) {
return {AC.Analysis.joinTypeErased(L.Lattice, R.Lattice),
Environment::join(L.Env, R.Env, AC.Analysis)};
Environment::join(L.Env, R.Env, AC.Analysis, JoinBehavior)};
}

public:
JoinedStateBuilder(AnalysisContext &AC) : AC(AC) {}
JoinedStateBuilder(AnalysisContext &AC,
Environment::ExprJoinBehavior JoinBehavior)
: AC(AC), JoinBehavior(JoinBehavior) {}

void addOwned(TypeErasedDataflowAnalysisState State) {
Owned.push_back(std::move(State));
Expand All @@ -248,12 +251,12 @@ class JoinedStateBuilder {
// initialize the state of each basic block differently.
return {AC.Analysis.typeErasedInitialElement(), AC.InitEnv.fork()};
if (All.size() == 1)
// Join the environment with itself so that we discard the entries from
// `ExprToLoc` and `ExprToVal`.
// Join the environment with itself so that we discard expression state if
// desired.
// FIXME: We could consider writing special-case code for this that only
// does the discarding, but it's not clear if this is worth it.
return {All[0]->Lattice,
Environment::join(All[0]->Env, All[0]->Env, AC.Analysis)};
return {All[0]->Lattice, Environment::join(All[0]->Env, All[0]->Env,
AC.Analysis, JoinBehavior)};

auto Result = join(*All[0], *All[1]);
for (unsigned I = 2; I < All.size(); ++I)
Expand Down Expand Up @@ -307,7 +310,22 @@ computeBlockInputState(const CFGBlock &Block, AnalysisContext &AC) {
}
}

JoinedStateBuilder Builder(AC);
// If any of the predecessor blocks contains an expression consumed in a
// different block, we need to keep expression state.
// Note that in this case, we keep expression state for all predecessors,
// rather than only those predecessors that actually contain an expression
// consumed in a different block. While this is potentially suboptimal, it's
// actually likely, if we have control flow within a full expression, that
// all predecessors have expression state consumed in a different block.
Environment::ExprJoinBehavior JoinBehavior = Environment::DiscardExprState;
for (const CFGBlock *Pred : Preds) {
if (Pred && AC.CFCtx.containsExprConsumedInDifferentBlock(*Pred)) {
JoinBehavior = Environment::KeepExprState;
break;
}
}

JoinedStateBuilder Builder(AC, JoinBehavior);
for (const CFGBlock *Pred : Preds) {
// Skip if the `Block` is unreachable or control flow cannot get past it.
if (!Pred || Pred->hasNoReturnElement())
Expand Down
8 changes: 0 additions & 8 deletions clang/lib/Basic/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -722,14 +722,6 @@ void VisibleModuleSet::setVisible(Module *M, SourceLocation Loc,
VisitModule({M, nullptr});
}

void VisibleModuleSet::makeTransitiveImportsVisible(Module *M,
SourceLocation Loc,
VisibleCallback Vis,
ConflictCallback Cb) {
for (auto *I : M->Imports)
setVisible(I, Loc, Vis, Cb);
}

ASTSourceDescriptor::ASTSourceDescriptor(Module &M)
: Signature(M.Signature), ClangModule(&M) {
if (M.Directory)
Expand Down
129 changes: 33 additions & 96 deletions clang/lib/Basic/OpenMPKinds.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -574,31 +574,7 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
}

bool clang::isOpenMPLoopDirective(OpenMPDirectiveKind DKind) {
return DKind == OMPD_simd || DKind == OMPD_for || DKind == OMPD_for_simd ||
DKind == OMPD_parallel_for || DKind == OMPD_parallel_for_simd ||
DKind == OMPD_taskloop || DKind == OMPD_taskloop_simd ||
DKind == OMPD_master_taskloop || DKind == OMPD_master_taskloop_simd ||
DKind == OMPD_parallel_master_taskloop ||
DKind == OMPD_parallel_master_taskloop_simd ||
DKind == OMPD_masked_taskloop || DKind == OMPD_masked_taskloop_simd ||
DKind == OMPD_parallel_masked_taskloop || DKind == OMPD_distribute ||
DKind == OMPD_parallel_masked_taskloop_simd ||
DKind == OMPD_target_parallel_for ||
DKind == OMPD_distribute_parallel_for ||
DKind == OMPD_distribute_parallel_for_simd ||
DKind == OMPD_distribute_simd ||
DKind == OMPD_target_parallel_for_simd || DKind == OMPD_target_simd ||
DKind == OMPD_teams_distribute ||
DKind == OMPD_teams_distribute_simd ||
DKind == OMPD_teams_distribute_parallel_for_simd ||
DKind == OMPD_teams_distribute_parallel_for ||
DKind == OMPD_target_teams_distribute ||
DKind == OMPD_target_teams_distribute_parallel_for ||
DKind == OMPD_target_teams_distribute_parallel_for_simd ||
DKind == OMPD_target_teams_distribute_simd || DKind == OMPD_tile ||
DKind == OMPD_unroll || DKind == OMPD_loop ||
DKind == OMPD_teams_loop || DKind == OMPD_target_teams_loop ||
DKind == OMPD_parallel_loop || DKind == OMPD_target_parallel_loop;
return getDirectiveAssociation(DKind) == Association::Loop;
}

bool clang::isOpenMPWorksharingDirective(OpenMPDirectiveKind DKind) {
Expand All @@ -619,44 +595,20 @@ bool clang::isOpenMPWorksharingDirective(OpenMPDirectiveKind DKind) {
}

bool clang::isOpenMPTaskLoopDirective(OpenMPDirectiveKind DKind) {
return DKind == OMPD_taskloop || DKind == OMPD_taskloop_simd ||
DKind == OMPD_master_taskloop || DKind == OMPD_master_taskloop_simd ||
DKind == OMPD_parallel_master_taskloop ||
DKind == OMPD_masked_taskloop || DKind == OMPD_masked_taskloop_simd ||
DKind == OMPD_parallel_masked_taskloop ||
DKind == OMPD_parallel_masked_taskloop_simd ||
DKind == OMPD_parallel_master_taskloop_simd;
return DKind == OMPD_taskloop ||
llvm::is_contained(getLeafConstructs(DKind), OMPD_taskloop);
}

bool clang::isOpenMPParallelDirective(OpenMPDirectiveKind DKind) {
return DKind == OMPD_parallel || DKind == OMPD_parallel_for ||
DKind == OMPD_parallel_for_simd || DKind == OMPD_parallel_sections ||
DKind == OMPD_target_parallel || DKind == OMPD_target_parallel_for ||
DKind == OMPD_distribute_parallel_for ||
DKind == OMPD_distribute_parallel_for_simd ||
DKind == OMPD_target_parallel_for_simd ||
DKind == OMPD_teams_distribute_parallel_for ||
DKind == OMPD_teams_distribute_parallel_for_simd ||
DKind == OMPD_target_teams_distribute_parallel_for ||
DKind == OMPD_target_teams_distribute_parallel_for_simd ||
DKind == OMPD_parallel_master || DKind == OMPD_parallel_masked ||
DKind == OMPD_parallel_master_taskloop ||
DKind == OMPD_parallel_master_taskloop_simd ||
DKind == OMPD_parallel_masked_taskloop ||
DKind == OMPD_parallel_masked_taskloop_simd ||
DKind == OMPD_parallel_loop || DKind == OMPD_target_parallel_loop ||
DKind == OMPD_teams_loop;
if (DKind == OMPD_teams_loop)
return true;
return DKind == OMPD_parallel ||
llvm::is_contained(getLeafConstructs(DKind), OMPD_parallel);
}

bool clang::isOpenMPTargetExecutionDirective(OpenMPDirectiveKind DKind) {
return DKind == OMPD_target || DKind == OMPD_target_parallel ||
DKind == OMPD_target_parallel_for ||
DKind == OMPD_target_parallel_for_simd || DKind == OMPD_target_simd ||
DKind == OMPD_target_teams || DKind == OMPD_target_teams_distribute ||
DKind == OMPD_target_teams_distribute_parallel_for ||
DKind == OMPD_target_teams_distribute_parallel_for_simd ||
DKind == OMPD_target_teams_distribute_simd ||
DKind == OMPD_target_teams_loop || DKind == OMPD_target_parallel_loop;
return DKind == OMPD_target ||
llvm::is_contained(getLeafConstructs(DKind), OMPD_target);
}

bool clang::isOpenMPTargetDataManagementDirective(OpenMPDirectiveKind DKind) {
Expand All @@ -665,60 +617,45 @@ bool clang::isOpenMPTargetDataManagementDirective(OpenMPDirectiveKind DKind) {
}

bool clang::isOpenMPNestingTeamsDirective(OpenMPDirectiveKind DKind) {
return DKind == OMPD_teams || DKind == OMPD_teams_distribute ||
DKind == OMPD_teams_distribute_simd ||
DKind == OMPD_teams_distribute_parallel_for_simd ||
DKind == OMPD_teams_distribute_parallel_for ||
DKind == OMPD_teams_loop;
if (DKind == OMPD_teams)
return true;
ArrayRef<Directive> Leaves = getLeafConstructs(DKind);
return !Leaves.empty() && Leaves.front() == OMPD_teams;
}

bool clang::isOpenMPTeamsDirective(OpenMPDirectiveKind DKind) {
return isOpenMPNestingTeamsDirective(DKind) || DKind == OMPD_target_teams ||
DKind == OMPD_target_teams_distribute ||
DKind == OMPD_target_teams_distribute_parallel_for ||
DKind == OMPD_target_teams_distribute_parallel_for_simd ||
DKind == OMPD_target_teams_distribute_simd ||
DKind == OMPD_target_teams_loop;
return DKind == OMPD_teams ||
llvm::is_contained(getLeafConstructs(DKind), OMPD_teams);
}

bool clang::isOpenMPSimdDirective(OpenMPDirectiveKind DKind) {
return DKind == OMPD_simd || DKind == OMPD_for_simd ||
DKind == OMPD_parallel_for_simd || DKind == OMPD_taskloop_simd ||
DKind == OMPD_master_taskloop_simd ||
DKind == OMPD_masked_taskloop_simd ||
DKind == OMPD_parallel_master_taskloop_simd ||
DKind == OMPD_parallel_masked_taskloop_simd ||
DKind == OMPD_distribute_parallel_for_simd ||
DKind == OMPD_distribute_simd || DKind == OMPD_target_simd ||
DKind == OMPD_teams_distribute_simd ||
DKind == OMPD_teams_distribute_parallel_for_simd ||
DKind == OMPD_target_teams_distribute_parallel_for_simd ||
DKind == OMPD_target_teams_distribute_simd ||
DKind == OMPD_target_parallel_for_simd;
// Avoid OMPD_declare_simd
if (getDirectiveAssociation(DKind) != Association::Loop)
return false;
// Formally, OMPD_end_do_simd also has a loop association, but
// it's a Fortran-specific directive.

return DKind == OMPD_simd ||
llvm::is_contained(getLeafConstructs(DKind), OMPD_simd);
}

bool clang::isOpenMPNestingDistributeDirective(OpenMPDirectiveKind Kind) {
return Kind == OMPD_distribute || Kind == OMPD_distribute_parallel_for ||
Kind == OMPD_distribute_parallel_for_simd ||
Kind == OMPD_distribute_simd;
// TODO add next directives.
if (Kind == OMPD_distribute)
return true;
ArrayRef<Directive> Leaves = getLeafConstructs(Kind);
return !Leaves.empty() && Leaves.front() == OMPD_distribute;
}

bool clang::isOpenMPDistributeDirective(OpenMPDirectiveKind Kind) {
return isOpenMPNestingDistributeDirective(Kind) ||
Kind == OMPD_teams_distribute || Kind == OMPD_teams_distribute_simd ||
Kind == OMPD_teams_distribute_parallel_for_simd ||
Kind == OMPD_teams_distribute_parallel_for ||
Kind == OMPD_target_teams_distribute ||
Kind == OMPD_target_teams_distribute_parallel_for ||
Kind == OMPD_target_teams_distribute_parallel_for_simd ||
Kind == OMPD_target_teams_distribute_simd;
return Kind == OMPD_distribute ||
llvm::is_contained(getLeafConstructs(Kind), OMPD_distribute);
}

bool clang::isOpenMPGenericLoopDirective(OpenMPDirectiveKind Kind) {
return Kind == OMPD_loop || Kind == OMPD_teams_loop ||
Kind == OMPD_target_teams_loop || Kind == OMPD_parallel_loop ||
Kind == OMPD_target_parallel_loop;
if (Kind == OMPD_loop)
return true;
ArrayRef<Directive> Leaves = getLeafConstructs(Kind);
return !Leaves.empty() && Leaves.back() == OMPD_loop;
}

bool clang::isOpenMPPrivate(OpenMPClauseKind Kind) {
Expand Down
26 changes: 24 additions & 2 deletions clang/lib/CodeGen/BackendUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,15 @@
#include "llvm/Transforms/Instrumentation/MemProfiler.h"
#include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
#include "llvm/Transforms/Instrumentation/PGOInstrumentation.h"
#include "llvm/Transforms/Instrumentation/RemoveTrapsPass.h"
#include "llvm/Transforms/Instrumentation/SanitizerBinaryMetadata.h"
#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
#include "llvm/Transforms/ObjCARC.h"
#include "llvm/Transforms/Scalar/EarlyCSE.h"
#include "llvm/Transforms/Scalar/GVN.h"
#include "llvm/Transforms/Scalar/JumpThreading.h"
#include "llvm/Transforms/Scalar/SimplifyCFG.h"
#include "llvm/Transforms/Utils/Debugify.h"
#include "llvm/Transforms/Utils/EntryExitInstrumenter.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
Expand All @@ -98,6 +100,10 @@ using namespace llvm;
namespace llvm {
extern cl::opt<bool> PrintPipelinePasses;

cl::opt<bool> ClRemoveTraps("clang-remove-traps", cl::Optional,
cl::desc("Insert remove-traps pass."),
cl::init(false));

// Experiment to move sanitizers earlier.
static cl::opt<bool> ClSanitizeOnOptimizerEarlyEP(
"sanitizer-early-opt-ep", cl::Optional,
Expand Down Expand Up @@ -356,8 +362,6 @@ static bool initTargetOptions(DiagnosticsEngine &Diags,
llvm::TargetMachine::parseBinutilsVersion(CodeGenOpts.BinutilsVersion);
Options.UseInitArray = CodeGenOpts.UseInitArray;
Options.DisableIntegratedAS = CodeGenOpts.DisableIntegratedAS;
Options.CompressDebugSections = CodeGenOpts.getCompressDebugSections();
Options.RelaxELFRelocations = CodeGenOpts.RelaxELFRelocations;

// Set EABI version.
Options.EABIVersion = TargetOpts.EABIVersion;
Expand Down Expand Up @@ -460,6 +464,9 @@ static bool initTargetOptions(DiagnosticsEngine &Diags,
Options.MCOptions.AsmVerbose = CodeGenOpts.AsmVerbose;
Options.MCOptions.Dwarf64 = CodeGenOpts.Dwarf64;
Options.MCOptions.PreserveAsmComments = CodeGenOpts.PreserveAsmComments;
Options.MCOptions.X86RelaxRelocations = CodeGenOpts.RelaxELFRelocations;
Options.MCOptions.CompressDebugSections =
CodeGenOpts.getCompressDebugSections();
Options.MCOptions.ABIName = TargetOpts.ABI;
for (const auto &Entry : HSOpts.UserEntries)
if (!Entry.IsFramework &&
Expand Down Expand Up @@ -743,6 +750,21 @@ static void addSanitizers(const Triple &TargetTriple,
// LastEP does not need GlobalsAA.
PB.registerOptimizerLastEPCallback(SanitizersCallback);
}

if (ClRemoveTraps) {
// We can optimize after inliner, and PGO profile matching. The hook below
// is called from `buildModuleOptimizationPipeline` just after profile use,
// and inliner is a part of `buildModuleSimplificationPipeline`, which is
// before `buildModuleOptimizationPipeline`.
PB.registerOptimizerEarlyEPCallback([&](ModulePassManager &MPM,
OptimizationLevel Level) {
FunctionPassManager FPM;
FPM.addPass(RemoveTrapsPass());
FPM.addPass(
SimplifyCFGPass(SimplifyCFGOptions().convertSwitchRangeToICmp(true)));
MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
});
}
}

void EmitAssemblyHelper::RunOptimizationPipeline(
Expand Down
50 changes: 47 additions & 3 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17963,6 +17963,12 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
return nullptr;

switch (BuiltinID) {
case Builtin::BI__builtin_hlsl_elementwise_any: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
return Builder.CreateIntrinsic(
/*ReturnType=*/llvm::Type::getInt1Ty(getLLVMContext()),
Intrinsic::dx_any, ArrayRef<Value *>{Op0}, nullptr, "dx.any");
}
case Builtin::BI__builtin_hlsl_dot: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
Value *Op1 = EmitScalarExpr(E->getArg(1));
Expand Down Expand Up @@ -17996,7 +18002,7 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
"Dot product requires vectors to be of the same size.");

return Builder.CreateIntrinsic(
/*ReturnType*/ T0->getScalarType(), Intrinsic::dx_dot,
/*ReturnType=*/T0->getScalarType(), Intrinsic::dx_dot,
ArrayRef<Value *>{Op0, Op1}, nullptr, "dx.dot");
} break;
case Builtin::BI__builtin_hlsl_lerp: {
Expand Down Expand Up @@ -18033,17 +18039,44 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
XVecTy->getElementType() == SVecTy->getElementType() &&
"Lerp requires float vectors to be of the same type.");
return Builder.CreateIntrinsic(
/*ReturnType*/ Xty, Intrinsic::dx_lerp, ArrayRef<Value *>{X, Y, S},
/*ReturnType=*/Xty, Intrinsic::dx_lerp, ArrayRef<Value *>{X, Y, S},
nullptr, "dx.lerp");
}
case Builtin::BI__builtin_hlsl_elementwise_frac: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
if (!E->getArg(0)->getType()->hasFloatingRepresentation())
llvm_unreachable("frac operand must have a float representation");
return Builder.CreateIntrinsic(
/*ReturnType*/ Op0->getType(), Intrinsic::dx_frac,
/*ReturnType=*/Op0->getType(), Intrinsic::dx_frac,
ArrayRef<Value *>{Op0}, nullptr, "dx.frac");
}
case Builtin::BI__builtin_hlsl_mad: {
Value *M = EmitScalarExpr(E->getArg(0));
Value *A = EmitScalarExpr(E->getArg(1));
Value *B = EmitScalarExpr(E->getArg(2));
if (E->getArg(0)->getType()->hasFloatingRepresentation()) {
return Builder.CreateIntrinsic(
/*ReturnType*/ M->getType(), Intrinsic::fmuladd,
ArrayRef<Value *>{M, A, B}, nullptr, "dx.fmad");
}
if (E->getArg(0)->getType()->hasSignedIntegerRepresentation()) {
return Builder.CreateIntrinsic(
/*ReturnType*/ M->getType(), Intrinsic::dx_imad,
ArrayRef<Value *>{M, A, B}, nullptr, "dx.imad");
}
assert(E->getArg(0)->getType()->hasUnsignedIntegerRepresentation());
return Builder.CreateIntrinsic(
/*ReturnType=*/M->getType(), Intrinsic::dx_umad,
ArrayRef<Value *>{M, A, B}, nullptr, "dx.umad");
}
case Builtin::BI__builtin_hlsl_elementwise_rcp: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
if (!E->getArg(0)->getType()->hasFloatingRepresentation())
llvm_unreachable("rcp operand must have a float representation");
return Builder.CreateIntrinsic(
/*ReturnType=*/Op0->getType(), Intrinsic::dx_rcp,
ArrayRef<Value *>{Op0}, nullptr, "dx.rcp");
}
}
return nullptr;
}
Expand Down Expand Up @@ -18406,6 +18439,17 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID,
CGM.getIntrinsic(Intrinsic::amdgcn_global_load_tr, {ArgTy});
return Builder.CreateCall(F, {Addr});
}
case AMDGPU::BI__builtin_amdgcn_get_fpenv: {
Function *F = CGM.getIntrinsic(Intrinsic::get_fpenv,
{llvm::Type::getInt64Ty(getLLVMContext())});
return Builder.CreateCall(F);
}
case AMDGPU::BI__builtin_amdgcn_set_fpenv: {
Function *F = CGM.getIntrinsic(Intrinsic::set_fpenv,
{llvm::Type::getInt64Ty(getLLVMContext())});
llvm::Value *Env = EmitScalarExpr(E->getArg(0));
return Builder.CreateCall(F, {Env});
}
case AMDGPU::BI__builtin_amdgcn_read_exec:
return EmitAMDGCNBallotForExec(*this, E, Int64Ty, Int64Ty, false);
case AMDGPU::BI__builtin_amdgcn_read_exec_lo:
Expand Down
20 changes: 14 additions & 6 deletions clang/lib/CodeGen/CGObjCMac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1593,12 +1593,20 @@ class CGObjCNonFragileABIMac : public CGObjCCommonMac {
}

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

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

public:
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -872,12 +872,12 @@ void CodeGenModule::Release() {
EmitMainVoidAlias();

if (getTriple().isAMDGPU()) {
// Emit amdgpu_code_object_version module flag, which is code object version
// Emit amdhsa_code_object_version module flag, which is code object version
// times 100.
if (getTarget().getTargetOpts().CodeObjectVersion !=
llvm::CodeObjectVersionKind::COV_None) {
getModule().addModuleFlag(llvm::Module::Error,
"amdgpu_code_object_version",
"amdhsa_code_object_version",
getTarget().getTargetOpts().CodeObjectVersion);
}

Expand Down Expand Up @@ -916,7 +916,7 @@ void CodeGenModule::Release() {
llvm::ConstantArray::get(ATy, UsedArray), "__clang_gpu_used_external");
addCompilerUsedGlobal(GV);
}
if (LangOpts.HIP) {
if (LangOpts.HIP && !getLangOpts().OffloadingNewDriver) {
// Emit a unique ID so that host and device binaries from the same
// compilation unit can be associated.
auto *GV = new llvm::GlobalVariable(
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/CodeGen/Targets/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -886,9 +886,11 @@ void AArch64ABIInfo::appendAttributeMangling(StringRef AttrStr,
return LHS.compare(RHS) < 0;
});

llvm::SmallDenseSet<StringRef, 8> UniqueFeats;
for (auto &Feat : Features)
if (auto Ext = llvm::AArch64::parseArchExtension(Feat))
Out << 'M' << Ext->Name;
if (UniqueFeats.insert(Ext->Name).second)
Out << 'M' << Ext->Name;
}

std::unique_ptr<TargetCodeGenInfo>
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3234,7 +3234,7 @@ class OffloadingActionBuilder final {
CudaActionBuilder(Compilation &C, DerivedArgList &Args,
const Driver::InputList &Inputs)
: CudaActionBuilderBase(C, Args, Inputs, Action::OFK_Cuda) {
DefaultCudaArch = CudaArch::SM_35;
DefaultCudaArch = CudaArch::CudaDefault;
}

StringRef getCanonicalOffloadArch(StringRef ArchStr) override {
Expand Down
Loading