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

## Check that BOLT correctly parses the Linux kernel .altinstructions section
## and annotates alternative instructions.

# 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
# RUN: llvm-bolt %t.exe --print-normalized --keep-nops -o %t.out \
# RUN: --alt-inst-feature-size=2 | FileCheck %s

## Older kernels used to have padlen field in alt_instr. Check compatibility.

# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown --defsym PADLEN=1 \
# RUN: %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
# RUN: llvm-bolt %t.exe --print-normalized --keep-nops --alt-inst-has-padlen \
# RUN: -o %t.out | FileCheck %s

## Check with a larger size of "feature" field in alt_instr.

# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown \
# RUN: --defsym FEATURE_SIZE_4=1 %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
# RUN: llvm-bolt %t.exe --print-normalized --keep-nops \
# RUN: --alt-inst-feature-size=4 -o %t.out | FileCheck %s

## Check that out-of-bounds read is handled properly.

# RUN: not llvm-bolt %t.exe --print-normalized --keep-nops \
# RUN: --alt-inst-feature-size=2 -o %t.out

# CHECK: BOLT-INFO: Linux kernel binary detected
# CHECK: BOLT-INFO: parsed 2 alternative instruction entries

.text
.globl _start
.type _start, %function
_start:
# CHECK: Binary Function "_start"
.L0:
rdtsc
# CHECK: rdtsc
# CHECK-SAME: AltInst: 1
# CHECK-SAME: AltInst2: 2
nop
# CHECK-NEXT: nop
# CHECK-SAME: AltInst: 1
# CHECK-SAME: AltInst2: 2
nop
nop
.L1:
ret
.size _start, .-_start

.section .altinstr_replacement,"ax",@progbits
.A0:
lfence
rdtsc
.A1:
rdtscp
.Ae:

## Alternative instruction info.
.section .altinstructions,"a",@progbits

.long .L0 - . # org instruction
.long .A0 - . # alt instruction
.ifdef FEATURE_SIZE_4
.long 0x72 # feature flags
.else
.word 0x72 # feature flags
.endif
.byte .L1 - .L0 # org size
.byte .A1 - .A0 # alt size
.ifdef PADLEN
.byte 0
.endif

.long .L0 - . # org instruction
.long .A1 - . # alt instruction
.ifdef FEATURE_SIZE_4
.long 0x3b # feature flags
.else
.word 0x3b # feature flags
.endif
.byte .L1 - .L0 # org size
.byte .Ae - .A1 # alt size
.ifdef PADLEN
.byte 0
.endif

## Fake Linux Kernel sections.
.section __ksymtab,"a",@progbits
.section __ksymtab_gpl,"a",@progbits
46 changes: 46 additions & 0 deletions bolt/test/X86/linux-bug-table.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# REQUIRES: system-linux

## Check that BOLT correctly parses the Linux kernel __bug_table 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 bug entry 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 bug table entries

.text
.globl _start
.type _start, %function
_start:
# CHECK: Binary Function "_start"
nop
.L0:
ud2
# CHECK: ud2
# CHECK-SAME: BugEntry: 1
nop
.L1:
ud2
# CHECK: ud2
# CHECK-SAME: BugEntry: 2
ret
.size _start, .-_start


## Bug table.
.section __bug_table,"a",@progbits
1:
.long .L0 - . # instruction
.org 1b + 12
2:
.long .L1 - . # instruction
.org 2b + 12

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

Expand Down
9 changes: 5 additions & 4 deletions clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,15 +155,16 @@ AST_MATCHER_P(DeclRefExpr, doesNotMutateObject, int, Indirections) {
if (const auto *const Member = dyn_cast<MemberExpr>(P)) {
if (const auto *const Method =
dyn_cast<CXXMethodDecl>(Member->getMemberDecl())) {
if (!Method->isConst()) {
// The method can mutate our variable.
return false;
if (Method->isConst() || Method->isStatic()) {
// The method call cannot mutate our variable.
continue;
}
continue;
return false;
}
Stack.emplace_back(Member, 0);
continue;
}

if (const auto *const Op = dyn_cast<UnaryOperator>(P)) {
switch (Op->getOpcode()) {
case UO_AddrOf:
Expand Down
8 changes: 7 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 All @@ -148,7 +152,9 @@ Changes in existing checks

- Improved :doc:`bugprone-unused-return-value
<clang-tidy/checks/bugprone/unused-return-value>` check by updating the
parameter `CheckedFunctions` to support regexp.
parameter `CheckedFunctions` to support regexp and avoiding false postive for
function with the same prefix as the default argument, e.g. ``std::unique_ptr``
and ``std::unique``.

- Improved :doc:`bugprone-use-after-move
<clang-tidy/checks/bugprone/use-after-move>` check to also handle
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,23 @@ Options
This parameter supports regexp. The function is checked if the name
and scope matches, with any arguments.
By default the following functions are checked:
``std::async, std::launder, std::remove, std::remove_if, std::unique,
std::unique_ptr::release, std::basic_string::empty, std::vector::empty,
std::back_inserter, std::distance, std::find, std::find_if, std::inserter,
std::lower_bound, std::make_pair, std::map::count, std::map::find,
std::map::lower_bound, std::multimap::equal_range,
std::multimap::upper_bound, std::set::count, std::set::find, std::setfill,
std::setprecision, std::setw, std::upper_bound, std::vector::at,
bsearch, ferror, feof, isalnum, isalpha, isblank, iscntrl, isdigit, isgraph,
islower, isprint, ispunct, isspace, isupper, iswalnum, iswprint, iswspace,
isxdigit, memchr, memcmp, strcmp, strcoll, strncmp, strpbrk, strrchr,
strspn, strstr, wcscmp, access, bind, connect, difftime, dlsym, fnmatch,
getaddrinfo, getopt, htonl, htons, iconv_open, inet_addr, isascii, isatty,
mmap, newlocale, openat, pathconf, pthread_equal, pthread_getspecific,
pthread_mutex_trylock, readdir, readlink, recvmsg, regexec, scandir,
semget, setjmp, shm_open, shmget, sigismember, strcasecmp, strsignal,
ttyname``
``::std::async$, ::std::launder$, ::std::remove$, ::std::remove_if$, ::std::unique$,
::std::unique_ptr::release$, ::std::basic_string::empty$, ::std::vector::empty$,
::std::back_inserter$, ::std::distance$, ::std::find$, ::std::find_if$, ::std::inserter$,
::std::lower_bound$, ::std::make_pair$, ::std::map::count$, ::std::map::find$,
::std::map::lower_bound$, ::std::multimap::equal_range$, ::std::multimap::upper_bound$,
::std::set::count$, ::std::set::find$, ::std::setfill$, ::std::setprecision$,
::std::setw$, ::std::upper_bound$, ::std::vector::at$, ::bsearch$, ::ferror$,
::feof$, ::isalnum$, ::isalpha$, ::isblank$, ::iscntrl$, ::isdigit$, ::isgraph$,
::islower$, ::isprint$, ::ispunct$, ::isspace$, ::isupper$, ::iswalnum$, ::iswprint$,
::iswspace$, ::isxdigit$, ::memchr$, ::memcmp$, ::strcmp$, ::strcoll$, ::strncmp$,
::strpbrk$, ::strrchr$, ::strspn$, ::strstr$, ::wcscmp$, ::access$, ::bind$,
::connect$, ::difftime$, ::dlsym$, ::fnmatch$, ::getaddrinfo$, ::getopt$,
::htonl$, ::htons$, ::iconv_open$, ::inet_addr$, isascii$, isatty$, ::mmap$,
::newlocale$, ::openat$, ::pathconf$, ::pthread_equal$, ::pthread_getspecific$,
::pthread_mutex_trylock$, ::readdir$, ::readlink$, ::recvmsg$, ::regexec$, ::scandir$,
::semget$, ::setjmp$, ::shm_open$, ::shmget$, ::sigismember$, ::strcasecmp$, ::strsignal$,
::ttyname$``

- ``std::async()``. Not using the return value makes the call synchronous.
- ``std::launder()``. Not using the return value usually means that the
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 @@ -30,6 +30,11 @@ struct default_delete;

template <typename T, typename Deleter = std::default_delete<T>>
struct unique_ptr {
unique_ptr();
unique_ptr(unique_ptr const&);
unique_ptr(unique_ptr &&);
unique_ptr& operator=(unique_ptr const&);
unique_ptr& operator=(unique_ptr &&);
T *release() noexcept;
};

Expand Down Expand Up @@ -254,3 +259,12 @@ void noWarning() {
({ std::async(increment, 42); });
auto StmtExprRetval = ({ std::async(increment, 42); });
}

namespace gh84314 {

extern std::unique_ptr<int> alloc();
void f1(std::unique_ptr<int> &foo) {
foo = alloc();
}

} // namespace gh84314
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ template <int Indirections> void RunTest(StringRef Snippet) {
void constMethod() const;
void nonConstMethod();
static void staticMethod();
void operator()(ConstTag) const;
void operator()(NonConstTag);
Expand Down Expand Up @@ -109,10 +111,12 @@ TEST(ConstReferenceDeclRefExprsTest, ConstValueVar) {
useConstPtr(&/*const*/target);
useConstPtrConstRef(&/*const*/target);
/*const*/target.constMethod();
/*const*/target.staticMethod();
/*const*/target(ConstTag{});
/*const*/target[42];
useConstRef((/*const*/target));
(/*const*/target).constMethod();
/*const*/target.staticMethod();
(void)(/*const*/target == /*const*/target);
(void)/*const*/target;
(void)&/*const*/target;
Expand Down Expand Up @@ -140,6 +144,7 @@ TEST(ConstReferenceDeclRefExprsTest, ConstRefVar) {
useConstPtr(&/*const*/target);
useConstPtrConstRef(&/*const*/target);
/*const*/target.constMethod();
/*const*/target.staticMethod();
/*const*/target(ConstTag{});
/*const*/target[42];
useConstRef((/*const*/target));
Expand Down Expand Up @@ -179,6 +184,7 @@ TEST(ConstReferenceDeclRefExprsTest, ValueVar) {
useConstPtr(&/*const*/target);
useConstPtrConstRef(&/*const*/target);
/*const*/target.constMethod();
/*const*/target.staticMethod();
target.nonConstMethod();
/*const*/target(ConstTag{});
target[42];
Expand Down Expand Up @@ -218,6 +224,7 @@ TEST(ConstReferenceDeclRefExprsTest, RefVar) {
useConstPtr(&/*const*/target);
useConstPtrConstRef(&/*const*/target);
/*const*/target.constMethod();
/*const*/target.staticMethod();
target.nonConstMethod();
/*const*/target(ConstTag{});
target[42];
Expand Down Expand Up @@ -256,6 +263,7 @@ TEST(ConstReferenceDeclRefExprsTest, PtrVar) {
useConstPtrConstRef(/*const*/target);
usePtrConstPtr(&target);
/*const*/target->constMethod();
/*const*/target->staticMethod();
target->nonConstMethod();
(*/*const*/target)(ConstTag{});
(*target)[42];
Expand Down Expand Up @@ -292,6 +300,7 @@ TEST(ConstReferenceDeclRefExprsTest, ConstPtrVar) {
useConstPtrConstPtr(&/*const*/target);
useConstPtrConstRef(/*const*/target);
/*const*/target->constMethod();
/*const*/target->staticMethod();
(*/*const*/target)(ConstTag{});
(*/*const*/target)[42];
/*const*/target->operator[](42);
Expand Down
1 change: 1 addition & 0 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5378,6 +5378,7 @@ The following builtin intrinsics can be used in constant expressions:
* ``__builtin_popcount``
* ``__builtin_popcountl``
* ``__builtin_popcountll``
* ``__builtin_popcountg``
* ``__builtin_rotateleft8``
* ``__builtin_rotateleft16``
* ``__builtin_rotateleft32``
Expand Down
15 changes: 15 additions & 0 deletions clang/docs/LibASTMatchersReference.html
Original file line number Diff line number Diff line change
Expand Up @@ -3546,6 +3546,21 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
</pre></td></tr>


<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>&gt;</td><td class="name" onclick="toggle('isExplicitObjectMemberFunction0')"><a name="isExplicitObjectMemberFunction0Anchor">isExplicitObjectMemberFunction</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isExplicitObjectMemberFunction0"><pre>Matches if the given method declaration declares a member function with an explicit object parameter.

Given
struct A {
int operator-(this A, int);
void fun(this A &&self);
static int operator()(int);
int operator+(int);
};

cxxMethodDecl(isExplicitObjectMemberFunction()) matches the first two methods but not the last two.
</pre></td></tr>


<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>&gt;</td><td class="name" onclick="toggle('isCopyAssignmentOperator0')"><a name="isCopyAssignmentOperator0Anchor">isCopyAssignmentOperator</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isCopyAssignmentOperator0"><pre>Matches if the given method declaration declares a copy assignment
operator.
Expand Down
27 changes: 25 additions & 2 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,18 @@ C++20 Feature Support
current module units.
Fixes `#84002 <https://github.com/llvm/llvm-project/issues/84002>`_.

- Initial support for class template argument deduction (CTAD) for type alias
templates (`P1814R0 <https://wg21.link/p1814r0>`_).
(#GH54051).

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 All @@ -113,6 +119,10 @@ Resolutions to C++ Defect Reports
of two types.
(`CWG1719: Layout compatibility and cv-qualification revisited <https://cplusplus.github.io/CWG/issues/1719.html>`_).

- Alignment of members is now respected when evaluating layout compatibility
of structs.
(`CWG2583: Common initial sequence should consider over-alignment <https://cplusplus.github.io/CWG/issues/2583.html>`_).

- ``[[no_unique_address]]`` is now respected when evaluating layout
compatibility of two types.
(`CWG2759: [[no_unique_address] and common initial sequence <https://cplusplus.github.io/CWG/issues/2759.html>`_).
Expand Down Expand Up @@ -155,6 +165,11 @@ Non-comprehensive list of changes in this release
- ``__builtin_addc``, ``__builtin_subc``, and the other sizes of those
builtins are now constexpr and may be used in constant expressions.

- Added ``__builtin_popcountg`` as a type-generic alternative to
``__builtin_popcount{,l,ll}`` with support for any unsigned integer type. Like
the previous builtins, this new builtin is constexpr and may be used in
constant expressions.

New Compiler Flags
------------------

Expand Down Expand Up @@ -239,6 +254,10 @@ Bug Fixes in This Version
for variables created through copy initialization having side-effects in C++17 and later.
Fixes (#GH64356) (#GH79518).

- Clang now emits errors for explicit specializations/instatiations of lambda call
operator.
Fixes (#GH83267).

Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down Expand Up @@ -317,8 +336,8 @@ Bug Fixes to C++ Support
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
Expand Down Expand Up @@ -387,6 +406,9 @@ RISC-V Support
CUDA/HIP Language Changes
^^^^^^^^^^^^^^^^^^^^^^^^^

- PTX is no longer included by default when compiling for CUDA. Using
``--cuda-include-ptx=all`` will return the old behavior.

CUDA Support
^^^^^^^^^^^^

Expand Down Expand Up @@ -415,6 +437,7 @@ AST Matchers
------------

- ``isInStdNamespace`` now supports Decl declared with ``extern "C++"``.
- Add ``isExplicitObjectMemberFunction``.

clang-format
------------
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/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -5843,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
19 changes: 19 additions & 0 deletions clang/include/clang/ASTMatchers/ASTMatchers.h
Original file line number Diff line number Diff line change
Expand Up @@ -6366,6 +6366,25 @@ AST_MATCHER(CXXMethodDecl, isConst) {
return Node.isConst();
}

/// Matches if the given method declaration declares a member function with an
/// explicit object parameter.
///
/// Given
/// \code
/// struct A {
/// int operator-(this A, int);
/// void fun(this A &&self);
/// static int operator()(int);
/// int operator+(int);
/// };
/// \endcode
///
/// cxxMethodDecl(isExplicitObjectMemberFunction()) matches the first two
/// methods but not the last two.
AST_MATCHER(CXXMethodDecl, isExplicitObjectMemberFunction) {
return Node.isExplicitObjectMemberFunction();
}

/// Matches if the given method declaration declares a copy assignment
/// operator.
///
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
16 changes: 15 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 Expand Up @@ -436,6 +445,11 @@ class Environment {
return createObjectInternal(&D, D.getType(), InitExpr);
}

/// Initializes the fields (including synthetic fields) of `Loc` with values,
/// unless values of the field type are not supported or we hit one of the
/// limits at which we stop producing values.
void initializeFieldsWithValues(RecordStorageLocation &Loc);

/// Assigns `Val` as the value of `Loc` in the environment.
void setValue(const StorageLocation &Loc, Value &Val);

Expand Down
8 changes: 8 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -983,6 +983,8 @@ def Availability : InheritableAttr {
.Case("watchos_app_extension", "watchOS (App Extension)")
.Case("maccatalyst", "macCatalyst")
.Case("maccatalyst_app_extension", "macCatalyst (App Extension)")
.Case("xros", "visionOS")
.Case("xros_app_extension", "visionOS (App Extension)")
.Case("swift", "Swift")
.Case("shadermodel", "HLSL ShaderModel")
.Case("ohos", "OpenHarmony OS")
Expand All @@ -1000,6 +1002,8 @@ static llvm::StringRef getPlatformNameSourceSpelling(llvm::StringRef Platform) {
.Case("watchos_app_extension", "watchOSApplicationExtension")
.Case("maccatalyst", "macCatalyst")
.Case("maccatalyst_app_extension", "macCatalystApplicationExtension")
.Case("xros", "visionOS")
.Case("xros_app_extension", "visionOSApplicationExtension")
.Case("zos", "z/OS")
.Case("shadermodel", "ShaderModel")
.Default(Platform);
Expand All @@ -1016,6 +1020,10 @@ static llvm::StringRef canonicalizePlatformName(llvm::StringRef Platform) {
.Case("watchOSApplicationExtension", "watchos_app_extension")
.Case("macCatalyst", "maccatalyst")
.Case("macCatalystApplicationExtension", "maccatalyst_app_extension")
.Case("visionOS", "xros")
.Case("visionOSApplicationExtension", "xros_app_extension")
.Case("visionos", "xros")
.Case("visionos_app_extension", "xros_app_extension")
.Case("ShaderModel", "shadermodel")
.Default(Platform);
} }];
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -706,7 +706,7 @@ def Popcount : Builtin, BitInt_Long_LongLongTemplate {

def Popcountg : Builtin {
let Spellings = ["__builtin_popcountg"];
let Attributes = [NoThrow, Const, CustomTypeChecking];
let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking];
let Prototype = "int(...)";
}

Expand Down
8 changes: 4 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
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/Cuda.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ enum class CudaArch {
LAST,

CudaDefault = CudaArch::SM_52,
HIPDefault = CudaArch::GFX803,
HIPDefault = CudaArch::GFX906,
};

static inline bool IsNVIDIAGpuArch(CudaArch A) {
Expand Down
24 changes: 24 additions & 0 deletions clang/include/clang/Basic/DarwinSDKInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,30 @@ class DarwinSDKInfo {
map(const VersionTuple &Key, const VersionTuple &MinimumValue,
std::optional<VersionTuple> MaximumValue) const;

/// Remap the 'introduced' availability version.
/// If None is returned, the 'unavailable' availability should be used
/// instead.
std::optional<VersionTuple>
mapIntroducedAvailabilityVersion(const VersionTuple &Key) const {
// API_TO_BE_DEPRECATED is 100000.
if (Key.getMajor() == 100000)
return VersionTuple(100000);
// Use None for maximum to force unavailable behavior for
return map(Key, MinimumValue, std::nullopt);
}

/// Remap the 'deprecated' and 'obsoleted' availability version.
/// If None is returned for 'obsoleted', the 'unavailable' availability
/// should be used instead. If None is returned for 'deprecated', the
/// 'deprecated' version should be dropped.
std::optional<VersionTuple>
mapDeprecatedObsoletedAvailabilityVersion(const VersionTuple &Key) const {
// API_TO_BE_DEPRECATED is 100000.
if (Key.getMajor() == 100000)
return VersionTuple(100000);
return map(Key, MinimumValue, MaximumValue);
}

static std::optional<RelatedTargetVersionMapping>
parseJSON(const llvm::json::Object &Obj,
VersionTuple MaximumDeploymentTarget);
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
38 changes: 17 additions & 21 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -2515,10 +2515,11 @@ def err_deduced_class_template_compound_type : Error<
"cannot %select{form pointer to|form reference to|form array of|"
"form function returning|use parentheses when declaring variable with}0 "
"deduced class template specialization type">;
def err_deduced_non_class_template_specialization_type : Error<
def err_deduced_non_class_or_alias_template_specialization_type : Error<
"%select{<error>|function template|variable template|alias template|"
"template template parameter|concept|template}0 %1 requires template "
"arguments; argument deduction only allowed for class templates">;
"arguments; argument deduction only allowed for class templates or alias "
"templates">;
def err_deduced_class_template_ctor_ambiguous : Error<
"ambiguous deduction for template arguments of %0">;
def err_deduced_class_template_ctor_no_viable : Error<
Expand Down Expand Up @@ -8170,6 +8171,8 @@ let CategoryName = "Lambda Issue" in {
def warn_cxx11_compat_generic_lambda : Warning<
"generic lambdas are incompatible with C++11">,
InGroup<CXXPre14Compat>, DefaultIgnore;
def err_lambda_explicit_spec : Error<
"lambda call operator should not be explicitly specialized or instantiated">;

// C++17 '*this' captures.
def warn_cxx14_compat_star_this_lambda_capture : Warning<
Expand Down Expand Up @@ -8199,6 +8202,11 @@ let CategoryName = "Lambda Issue" in {
def warn_cxx17_compat_lambda_def_ctor_assign : Warning<
"%select{default construction|assignment}0 of lambda is incompatible with "
"C++ standards before C++20">, InGroup<CXXPre20Compat>, DefaultIgnore;

// C++20 class template argument deduction for alias templates.
def warn_cxx17_compat_ctad_for_alias_templates : Warning<
"class template argument deduction for alias templates is incompatible with "
"C++ standards before C++20">, InGroup<CXXPre20Compat>, DefaultIgnore;
}

def err_return_in_captured_stmt : Error<
Expand Down Expand Up @@ -9607,13 +9615,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 @@ -9724,21 +9729,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<
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 a C++23 extension">,
InGroup<DiagGroup<"c++23-default-comp-relaxed-constexpr">>;
def warn_cxx23_compat_defaulted_comparison_constexpr_mismatch : Warning<
"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
4 changes: 3 additions & 1 deletion clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -7414,7 +7414,9 @@ def ast_view : Flag<["-"], "ast-view">,
def emit_module : Flag<["-"], "emit-module">,
HelpText<"Generate pre-compiled module file from a module map">;
def emit_module_interface : Flag<["-"], "emit-module-interface">,
HelpText<"Generate pre-compiled module file from a C++ module interface">;
HelpText<"Generate pre-compiled module file from a standard C++ module interface unit">;
def emit_reduced_module_interface : Flag<["-"], "emit-reduced-module-interface">,
HelpText<"Generate reduced prebuilt module interface from a standard C++ module interface unit">;
def emit_header_unit : Flag<["-"], "emit-header-unit">,
HelpText<"Generate C++20 header units from header files">;
def emit_pch : Flag<["-"], "emit-pch">,
Expand Down
15 changes: 14 additions & 1 deletion clang/include/clang/Frontend/FrontendActions.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ class GenerateModuleAction : public ASTFrontendAction {
CreateOutputFile(CompilerInstance &CI, StringRef InFile) = 0;

protected:
std::vector<std::unique_ptr<ASTConsumer>>
CreateMultiplexConsumer(CompilerInstance &CI, StringRef InFile);

std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) override;

Expand Down Expand Up @@ -147,8 +150,10 @@ class GenerateModuleFromModuleMapAction : public GenerateModuleAction {
CreateOutputFile(CompilerInstance &CI, StringRef InFile) override;
};

/// Generates full BMI (which contains full information to generate the object
/// files) for C++20 Named Modules.
class GenerateModuleInterfaceAction : public GenerateModuleAction {
private:
protected:
bool BeginSourceFileAction(CompilerInstance &CI) override;

std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
Expand All @@ -158,6 +163,14 @@ class GenerateModuleInterfaceAction : public GenerateModuleAction {
CreateOutputFile(CompilerInstance &CI, StringRef InFile) override;
};

/// Only generates the reduced BMI. This action is mainly used by tests.
class GenerateReducedModuleInterfaceAction
: public GenerateModuleInterfaceAction {
private:
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) override;
};

class GenerateHeaderUnitAction : public GenerateModuleAction {

private:
Expand Down
6 changes: 5 additions & 1 deletion clang/include/clang/Frontend/FrontendOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,13 @@ enum ActionKind {
/// Generate pre-compiled module from a module map.
GenerateModule,

/// Generate pre-compiled module from a C++ module interface file.
/// Generate pre-compiled module from a standard C++ module interface unit.
GenerateModuleInterface,

/// Generate reduced module interface for a standard C++ module interface
/// unit.
GenerateReducedModuleInterface,

/// Generate a C++20 header unit module from a header file.
GenerateHeaderUnit,

Expand Down
5 changes: 4 additions & 1 deletion clang/include/clang/InstallAPI/Frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,15 @@ class FrontendRecordsSlice : public llvm::MachO::RecordsSlice {
/// \param D The pointer to the declaration from traversing AST.
/// \param Access The intended access level of symbol.
/// \param Flags The flags that describe attributes of the symbol.
/// \param Inlined Whether declaration is inlined, only applicable to
/// functions.
/// \return The non-owning pointer to added record in slice.
GlobalRecord *addGlobal(StringRef Name, RecordLinkage Linkage,
GlobalRecord::Kind GV,
const clang::AvailabilityInfo Avail, const Decl *D,
const HeaderType Access,
SymbolFlags Flags = SymbolFlags::None);
SymbolFlags Flags = SymbolFlags::None,
bool Inlined = false);

/// Add ObjC Class record with attributes from AST.
///
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/InstallAPI/Visitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ class InstallAPIVisitor final : public ASTConsumer,
/// Collect global variables.
bool VisitVarDecl(const VarDecl *D);

/// Collect global functions.
bool VisitFunctionDecl(const FunctionDecl *D);

/// Collect Objective-C Interface declarations.
/// Every Objective-C class has an interface declaration that lists all the
/// ivars, properties, and methods of the class.
Expand Down
5 changes: 4 additions & 1 deletion clang/include/clang/Interpreter/Interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ class IncrementalCompilerBuilder {
UserArgs = Args;
}

void SetTargetTriple(std::string TT) { TargetTriple = TT; }

// General C++
llvm::Expected<std::unique_ptr<CompilerInstance>> CreateCpp();

Expand All @@ -62,11 +64,12 @@ class IncrementalCompilerBuilder {

private:
static llvm::Expected<std::unique_ptr<CompilerInstance>>
create(std::vector<const char *> &ClangArgv);
create(std::string TT, std::vector<const char *> &ClangArgv);

llvm::Expected<std::unique_ptr<CompilerInstance>> createCuda(bool device);

std::vector<const char *> UserArgs;
std::optional<std::string> TargetTriple;

llvm::StringRef OffloadArch;
llvm::StringRef CudaSDKPath;
Expand Down
30 changes: 22 additions & 8 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -3263,7 +3263,8 @@ class Sema final {
Decl *ActOnFileScopeAsmDecl(Expr *expr, SourceLocation AsmLoc,
SourceLocation RParenLoc);

Decl *ActOnTopLevelStmtDecl(Stmt *Statement);
TopLevelStmtDecl *ActOnStartTopLevelStmtDecl(Scope *S);
void ActOnFinishTopLevelStmtDecl(TopLevelStmtDecl *D, Stmt *Statement);

void ActOnPopScope(SourceLocation Loc, Scope *S);

Expand Down Expand Up @@ -9826,6 +9827,12 @@ class Sema final {
ArrayRef<TemplateArgument> TemplateArgs,
sema::TemplateDeductionInfo &Info);

TemplateDeductionResult DeduceTemplateArguments(
TemplateParameterList *TemplateParams, ArrayRef<TemplateArgument> Ps,
ArrayRef<TemplateArgument> As, sema::TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
bool NumberOfArgumentsMustMatch);

TemplateDeductionResult SubstituteExplicitTemplateArguments(
FunctionTemplateDecl *FunctionTemplate,
TemplateArgumentListInfo &ExplicitTemplateArgs,
Expand Down Expand Up @@ -10377,6 +10384,9 @@ class Sema final {
InstantiatingTemplate &operator=(const InstantiatingTemplate &) = delete;
};

bool SubstTemplateArgument(const TemplateArgumentLoc &Input,
const MultiLevelTemplateArgumentList &TemplateArgs,
TemplateArgumentLoc &Output);
bool
SubstTemplateArguments(ArrayRef<TemplateArgumentLoc> Args,
const MultiLevelTemplateArgumentList &TemplateArgs,
Expand Down Expand Up @@ -10861,9 +10871,11 @@ class Sema final {
ParmVarDecl *Param);
void InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
FunctionDecl *Function);
FunctionDecl *InstantiateFunctionDeclaration(FunctionTemplateDecl *FTD,
const TemplateArgumentList *Args,
SourceLocation Loc);
FunctionDecl *InstantiateFunctionDeclaration(
FunctionTemplateDecl *FTD, const TemplateArgumentList *Args,
SourceLocation Loc,
CodeSynthesisContext::SynthesisKind CSC =
CodeSynthesisContext::ExplicitTemplateArgumentSubstitution);
void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
FunctionDecl *Function,
bool Recursive = false,
Expand Down Expand Up @@ -11606,12 +11618,14 @@ class Sema final {
LocalInstantiationScope &Scope,
const MultiLevelTemplateArgumentList &TemplateArgs);

/// used by SetupConstraintCheckingTemplateArgumentsAndScope to recursively(in
/// Used by SetupConstraintCheckingTemplateArgumentsAndScope to recursively(in
/// the case of lambdas) set up the LocalInstantiationScope of the current
/// function.
bool SetupConstraintScope(
FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs,
MultiLevelTemplateArgumentList MLTAL, LocalInstantiationScope &Scope);
bool
SetupConstraintScope(FunctionDecl *FD,
std::optional<ArrayRef<TemplateArgument>> TemplateArgs,
const MultiLevelTemplateArgumentList &MLTAL,
LocalInstantiationScope &Scope);

/// Used during constraint checking, sets up the constraint template argument
/// lists, and calls SetupConstraintScope to set up the
Expand Down
32 changes: 30 additions & 2 deletions clang/include/clang/Serialization/ASTWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,10 @@ class ASTWriter : public ASTDeserializationListener,
/// Indicates that the AST contained compiler errors.
bool ASTHasCompilerErrors = false;

/// Indicates that we're going to generate the reduced BMI for C++20
/// named modules.
bool GeneratingReducedBMI = false;

/// Mapping from input file entries to the index into the
/// offset table where information about that input file is stored.
llvm::DenseMap<const FileEntry *, uint32_t> InputFileIDs;
Expand Down Expand Up @@ -596,7 +600,8 @@ class ASTWriter : public ASTDeserializationListener,
ASTWriter(llvm::BitstreamWriter &Stream, SmallVectorImpl<char> &Buffer,
InMemoryModuleCache &ModuleCache,
ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
bool IncludeTimestamps = true, bool BuildingImplicitModule = false);
bool IncludeTimestamps = true, bool BuildingImplicitModule = false,
bool GeneratingReducedBMI = false);
~ASTWriter() override;

ASTContext &getASTContext() const {
Expand Down Expand Up @@ -856,14 +861,22 @@ class PCHGenerator : public SemaConsumer {
const ASTWriter &getWriter() const { return Writer; }
SmallVectorImpl<char> &getPCH() const { return Buffer->Data; }

bool isComplete() const { return Buffer->IsComplete; }
PCHBuffer *getBufferPtr() { return Buffer.get(); }
StringRef getOutputFile() const { return OutputFile; }
DiagnosticsEngine &getDiagnostics() const {
return SemaPtr->getDiagnostics();
}

public:
PCHGenerator(const Preprocessor &PP, InMemoryModuleCache &ModuleCache,
StringRef OutputFile, StringRef isysroot,
std::shared_ptr<PCHBuffer> Buffer,
ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
bool AllowASTWithErrors = false, bool IncludeTimestamps = true,
bool BuildingImplicitModule = false,
bool ShouldCacheASTInMemory = false);
bool ShouldCacheASTInMemory = false,
bool GeneratingReducedBMI = false);
~PCHGenerator() override;

void InitializeSema(Sema &S) override { SemaPtr = &S; }
Expand All @@ -873,6 +886,21 @@ class PCHGenerator : public SemaConsumer {
bool hasEmittedPCH() const { return Buffer->IsComplete; }
};

class ReducedBMIGenerator : public PCHGenerator {
public:
ReducedBMIGenerator(const Preprocessor &PP, InMemoryModuleCache &ModuleCache,
StringRef OutputFile, std::shared_ptr<PCHBuffer> Buffer,
bool IncludeTimestamps);

void HandleTranslationUnit(ASTContext &Ctx) override;
};

/// If we can elide the definition of \param D in reduced BMI.
///
/// Generally, we can elide the definition of a declaration if it won't affect
/// the ABI. e.g., the non-inline function bodies.
bool CanElideDeclDef(const Decl *D);

/// A simple helper class to pack several bits in order into (a) 32 bit
/// integer(s).
class BitsPacker {
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Testing/CommandLineArgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ enum TestLanguage {
Lang_CXX14,
Lang_CXX17,
Lang_CXX20,
Lang_CXX23,
Lang_OpenCL,
Lang_OBJC,
Lang_OBJCXX
Expand Down
16 changes: 11 additions & 5 deletions clang/include/clang/Testing/TestClangConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,24 +34,30 @@ struct TestClangConfig {
bool isCXX() const {
return Language == Lang_CXX03 || Language == Lang_CXX11 ||
Language == Lang_CXX14 || Language == Lang_CXX17 ||
Language == Lang_CXX20;
Language == Lang_CXX20 || Language == Lang_CXX23;
}

bool isCXX11OrLater() const {
return Language == Lang_CXX11 || Language == Lang_CXX14 ||
Language == Lang_CXX17 || Language == Lang_CXX20;
Language == Lang_CXX17 || Language == Lang_CXX20 ||
Language == Lang_CXX23;
}

bool isCXX14OrLater() const {
return Language == Lang_CXX14 || Language == Lang_CXX17 ||
Language == Lang_CXX20;
Language == Lang_CXX20 || Language == Lang_CXX23;
}

bool isCXX17OrLater() const {
return Language == Lang_CXX17 || Language == Lang_CXX20;
return Language == Lang_CXX17 || Language == Lang_CXX20 ||
Language == Lang_CXX23;
}

bool isCXX20OrLater() const { return Language == Lang_CXX20; }
bool isCXX20OrLater() const {
return Language == Lang_CXX20 || Language == Lang_CXX23;
}

bool isCXX23OrLater() const { return Language == Lang_CXX23; }

bool supportsCXXDynamicExceptionSpecification() const {
return Language == Lang_CXX03 || Language == Lang_CXX11 ||
Expand Down
11 changes: 8 additions & 3 deletions clang/lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5552,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 @@ -5572,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
1 change: 1 addition & 0 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12483,6 +12483,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
case Builtin::BI__builtin_popcount:
case Builtin::BI__builtin_popcountl:
case Builtin::BI__builtin_popcountll:
case Builtin::BI__builtin_popcountg:
case Builtin::BI__popcnt16: // Microsoft variants of popcount
case Builtin::BI__popcnt:
case Builtin::BI__popcnt64: {
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
14 changes: 14 additions & 0 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1959,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
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
1 change: 1 addition & 0 deletions clang/lib/ASTMatchers/Dynamic/Registry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(isExpansionInMainFile);
REGISTER_MATCHER(isExpansionInSystemHeader);
REGISTER_MATCHER(isExplicit);
REGISTER_MATCHER(isExplicitObjectMemberFunction);
REGISTER_MATCHER(isExplicitTemplateSpecialization);
REGISTER_MATCHER(isExpr);
REGISTER_MATCHER(isExternC);
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
49 changes: 43 additions & 6 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 @@ -414,8 +432,15 @@ void Environment::initialize() {
}
} else if (MethodDecl->isImplicitObjectMemberFunction()) {
QualType ThisPointeeType = MethodDecl->getFunctionObjectParameterType();
setThisPointeeStorageLocation(
cast<RecordStorageLocation>(createObject(ThisPointeeType)));
auto &ThisLoc =
cast<RecordStorageLocation>(createStorageLocation(ThisPointeeType));
setThisPointeeStorageLocation(ThisLoc);
refreshRecordValue(ThisLoc, *this);
// Initialize fields of `*this` with values, but only if we're not
// analyzing a constructor; after all, it's the constructor's job to do
// this (and we want to be able to test that).
if (!isa<CXXConstructorDecl>(MethodDecl))
initializeFieldsWithValues(ThisLoc);
}
}
}
Expand Down Expand Up @@ -627,7 +652,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 +701,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 Expand Up @@ -799,6 +826,16 @@ PointerValue &Environment::getOrCreateNullPointerValue(QualType PointeeType) {
return DACtx->getOrCreateNullPointerValue(PointeeType);
}

void Environment::initializeFieldsWithValues(RecordStorageLocation &Loc) {
llvm::DenseSet<QualType> Visited;
int CreatedValuesCount = 0;
initializeFieldsWithValues(Loc, Visited, 0, CreatedValuesCount);
if (CreatedValuesCount > MaxCompositeValueSize) {
llvm::errs() << "Attempting to initialize a huge value of type: "
<< Loc.getType() << '\n';
}
}

void Environment::setValue(const StorageLocation &Loc, Value &Val) {
assert(!isa<RecordValue>(&Val) || &cast<RecordValue>(&Val)->getLoc() == &Loc);

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
34 changes: 26 additions & 8 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 Expand Up @@ -388,7 +406,6 @@ builtinTransferInitializer(const CFGInitializer &Elt,
}
}
assert(Member != nullptr);
assert(MemberLoc != nullptr);

// FIXME: Instead of these case distinctions, we would ideally want to be able
// to simply use `Environment::createObject()` here, the same way that we do
Expand All @@ -404,6 +421,7 @@ builtinTransferInitializer(const CFGInitializer &Elt,

ParentLoc->setChild(*Member, InitExprLoc);
} else if (auto *InitExprVal = Env.getValue(*InitExpr)) {
assert(MemberLoc != nullptr);
if (Member->getType()->isRecordType()) {
auto *InitValStruct = cast<RecordValue>(InitExprVal);
// FIXME: Rather than performing a copy here, we should really be
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/CodeGen/BackendUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -356,8 +356,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 +458,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
2 changes: 1 addition & 1 deletion clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
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
10 changes: 9 additions & 1 deletion clang/lib/Driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3373,7 +3373,7 @@ class OffloadingActionBuilder final {
const Driver::InputList &Inputs)
: CudaActionBuilderBase(C, Args, Inputs, Action::OFK_HIP) {

DefaultCudaArch = CudaArch::GFX906;
DefaultCudaArch = CudaArch::HIPDefault;

if (Args.hasArg(options::OPT_fhip_emit_relocatable,
options::OPT_fno_hip_emit_relocatable)) {
Expand Down Expand Up @@ -4625,7 +4625,15 @@ Action *Driver::BuildOffloadingActions(Compilation &C,
DDeps.add(*A, *TCAndArch->first, TCAndArch->second.data(), Kind);
OffloadAction::DeviceDependences DDep;
DDep.add(*A, *TCAndArch->first, TCAndArch->second.data(), Kind);

// Compiling CUDA in non-RDC mode uses the PTX output if available.
for (Action *Input : A->getInputs())
if (Kind == Action::OFK_Cuda && A->getType() == types::TY_Object &&
!Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc,
false))
DDep.add(*Input, *TCAndArch->first, TCAndArch->second.data(), Kind);
OffloadActions.push_back(C.MakeAction<OffloadAction>(DDep, A->getType()));

++TCAndArch;
}
}
Expand Down
30 changes: 23 additions & 7 deletions clang/lib/Driver/OffloadBundler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -590,7 +590,8 @@ class ObjectFileHandler final : public FileHandler {
// Copy fat object contents to the output when extracting host bundle.
std::string ModifiedContent;
if (Content.size() == 1u && Content.front() == 0) {
auto HostBundleOrErr = getHostBundle();
auto HostBundleOrErr = getHostBundle(
StringRef(Input.getBufferStart(), Input.getBufferSize()));
if (!HostBundleOrErr)
return HostBundleOrErr.takeError();

Expand Down Expand Up @@ -700,7 +701,7 @@ class ObjectFileHandler final : public FileHandler {
return Error::success();
}

Expected<std::string> getHostBundle() {
Expected<std::string> getHostBundle(StringRef Input) {
TempFileHandlerRAII TempFiles;

auto ModifiedObjPathOrErr = TempFiles.Create(std::nullopt);
Expand All @@ -715,7 +716,24 @@ class ObjectFileHandler final : public FileHandler {
ObjcopyArgs.push_back("--regex");
ObjcopyArgs.push_back("--remove-section=__CLANG_OFFLOAD_BUNDLE__.*");
ObjcopyArgs.push_back("--");
ObjcopyArgs.push_back(BundlerConfig.InputFileNames.front());

StringRef ObjcopyInputFileName;
// When unbundling an archive, the content of each object file in the
// archive is passed to this function by parameter Input, which is different
// from the content of the original input archive file, therefore it needs
// to be saved to a temporary file before passed to llvm-objcopy. Otherwise,
// Input is the same as the content of the original input file, therefore
// temporary file is not needed.
if (StringRef(BundlerConfig.FilesType).starts_with("a")) {
auto InputFileOrErr =
TempFiles.Create(ArrayRef<char>(Input.data(), Input.size()));
if (!InputFileOrErr)
return InputFileOrErr.takeError();
ObjcopyInputFileName = *InputFileOrErr;
} else
ObjcopyInputFileName = BundlerConfig.InputFileNames.front();

ObjcopyArgs.push_back(ObjcopyInputFileName);
ObjcopyArgs.push_back(ModifiedObjPath);

if (Error Err = executeObjcopy(BundlerConfig.ObjcopyPath, ObjcopyArgs))
Expand Down Expand Up @@ -1628,10 +1646,8 @@ Error OffloadBundler::UnbundleArchive() {
while (!CodeObject.empty()) {
SmallVector<StringRef> CompatibleTargets;
auto CodeObjectInfo = OffloadTargetInfo(CodeObject, BundlerConfig);
if (CodeObjectInfo.hasHostKind()) {
// Do nothing, we don't extract host code yet.
} else if (getCompatibleOffloadTargets(CodeObjectInfo, CompatibleTargets,
BundlerConfig)) {
if (getCompatibleOffloadTargets(CodeObjectInfo, CompatibleTargets,
BundlerConfig)) {
std::string BundleData;
raw_string_ostream DataStream(BundleData);
if (Error Err = FileHandler->ReadBundle(DataStream, CodeObjectBuffer))
Expand Down
19 changes: 14 additions & 5 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4478,14 +4478,20 @@ renderDebugOptions(const ToolChain &TC, const Driver &D, const llvm::Triple &T,
Args.getLastArg(options::OPT_ggnu_pubnames, options::OPT_gno_gnu_pubnames,
options::OPT_gpubnames, options::OPT_gno_pubnames);
if (DwarfFission != DwarfFissionKind::None ||
(PubnamesArg && checkDebugInfoOption(PubnamesArg, Args, D, TC)))
if (!PubnamesArg ||
(!PubnamesArg->getOption().matches(options::OPT_gno_gnu_pubnames) &&
!PubnamesArg->getOption().matches(options::OPT_gno_pubnames)))
(PubnamesArg && checkDebugInfoOption(PubnamesArg, Args, D, TC))) {
const bool OptionSet =
(PubnamesArg &&
(PubnamesArg->getOption().matches(options::OPT_gpubnames) ||
PubnamesArg->getOption().matches(options::OPT_ggnu_pubnames)));
if ((DebuggerTuning != llvm::DebuggerKind::LLDB || OptionSet) &&
(!PubnamesArg ||
(!PubnamesArg->getOption().matches(options::OPT_gno_gnu_pubnames) &&
!PubnamesArg->getOption().matches(options::OPT_gno_pubnames))))
CmdArgs.push_back(PubnamesArg && PubnamesArg->getOption().matches(
options::OPT_gpubnames)
? "-gpubnames"
: "-ggnu-pubnames");
}
const auto *SimpleTemplateNamesArg =
Args.getLastArg(options::OPT_gsimple_template_names,
options::OPT_gno_simple_template_names);
Expand Down Expand Up @@ -8886,10 +8892,13 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA,
// Add the linker arguments to be forwarded by the wrapper.
CmdArgs.push_back(Args.MakeArgString(Twine("--linker-path=") +
LinkCommand->getExecutable()));
CmdArgs.push_back("--");
for (const char *LinkArg : LinkCommand->getArguments())
CmdArgs.push_back(LinkArg);

if (Args.hasFlag(options::OPT_offload_compress,
options::OPT_no_offload_compress, false))
CmdArgs.push_back("--compress");

const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("clang-linker-wrapper"));

Expand Down
22 changes: 12 additions & 10 deletions clang/lib/Driver/ToolChains/Cuda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -503,18 +503,20 @@ void NVPTX::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
Exec, CmdArgs, Inputs, Output));
}

static bool shouldIncludePTX(const ArgList &Args, const char *gpu_arch) {
bool includePTX = true;
for (Arg *A : Args) {
if (!(A->getOption().matches(options::OPT_cuda_include_ptx_EQ) ||
A->getOption().matches(options::OPT_no_cuda_include_ptx_EQ)))
continue;
static bool shouldIncludePTX(const ArgList &Args, StringRef InputArch) {
// The new driver does not include PTX by default to avoid overhead.
bool includePTX = !Args.hasFlag(options::OPT_offload_new_driver,
options::OPT_no_offload_new_driver, false);
for (Arg *A : Args.filtered(options::OPT_cuda_include_ptx_EQ,
options::OPT_no_cuda_include_ptx_EQ)) {
A->claim();
const StringRef ArchStr = A->getValue();
if (ArchStr == "all" || ArchStr == gpu_arch) {
includePTX = A->getOption().matches(options::OPT_cuda_include_ptx_EQ);
continue;
}
if (A->getOption().matches(options::OPT_cuda_include_ptx_EQ) &&
(ArchStr == "all" || ArchStr == InputArch))
includePTX = true;
else if (A->getOption().matches(options::OPT_no_cuda_include_ptx_EQ) &&
(ArchStr == "all" || ArchStr == InputArch))
includePTX = false;
}
return includePTX;
}
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2556,6 +2556,8 @@ static const auto &getFrontendActionTable() {

{frontend::GenerateModule, OPT_emit_module},
{frontend::GenerateModuleInterface, OPT_emit_module_interface},
{frontend::GenerateReducedModuleInterface,
OPT_emit_reduced_module_interface},
{frontend::GenerateHeaderUnit, OPT_emit_header_unit},
{frontend::GeneratePCH, OPT_emit_pch},
{frontend::GenerateInterfaceStubs, OPT_emit_interface_stubs},
Expand Down Expand Up @@ -4280,6 +4282,7 @@ static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) {
case frontend::FixIt:
case frontend::GenerateModule:
case frontend::GenerateModuleInterface:
case frontend::GenerateReducedModuleInterface:
case frontend::GenerateHeaderUnit:
case frontend::GeneratePCH:
case frontend::GenerateInterfaceStubs:
Expand Down
37 changes: 31 additions & 6 deletions clang/lib/Frontend/FrontendActions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,12 +184,12 @@ bool GeneratePCHAction::BeginSourceFileAction(CompilerInstance &CI) {
return true;
}

std::unique_ptr<ASTConsumer>
GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
std::vector<std::unique_ptr<ASTConsumer>>
GenerateModuleAction::CreateMultiplexConsumer(CompilerInstance &CI,
StringRef InFile) {
std::unique_ptr<raw_pwrite_stream> OS = CreateOutputFile(CI, InFile);
if (!OS)
return nullptr;
return {};

std::string OutputFile = CI.getFrontendOpts().OutputFile;
std::string Sysroot;
Expand All @@ -210,6 +210,17 @@ GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI,
+CI.getFrontendOpts().BuildingImplicitModule));
Consumers.push_back(CI.getPCHContainerWriter().CreatePCHContainerGenerator(
CI, std::string(InFile), OutputFile, std::move(OS), Buffer));
return Consumers;
}

std::unique_ptr<ASTConsumer>
GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
std::vector<std::unique_ptr<ASTConsumer>> Consumers =
CreateMultiplexConsumer(CI, InFile);
if (Consumers.empty())
return nullptr;

return std::make_unique<MultiplexConsumer>(std::move(Consumers));
}

Expand Down Expand Up @@ -265,7 +276,12 @@ GenerateModuleInterfaceAction::CreateASTConsumer(CompilerInstance &CI,
CI.getHeaderSearchOpts().ModulesSkipHeaderSearchPaths = true;
CI.getHeaderSearchOpts().ModulesSkipPragmaDiagnosticMappings = true;

return GenerateModuleAction::CreateASTConsumer(CI, InFile);
std::vector<std::unique_ptr<ASTConsumer>> Consumers =
CreateMultiplexConsumer(CI, InFile);
if (Consumers.empty())
return nullptr;

return std::make_unique<MultiplexConsumer>(std::move(Consumers));
}

std::unique_ptr<raw_pwrite_stream>
Expand All @@ -274,6 +290,16 @@ GenerateModuleInterfaceAction::CreateOutputFile(CompilerInstance &CI,
return CI.createDefaultOutputFile(/*Binary=*/true, InFile, "pcm");
}

std::unique_ptr<ASTConsumer>
GenerateReducedModuleInterfaceAction::CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
auto Buffer = std::make_shared<PCHBuffer>();
return std::make_unique<ReducedBMIGenerator>(
CI.getPreprocessor(), CI.getModuleCache(),
CI.getFrontendOpts().OutputFile, Buffer,
/*IncludeTimestamps=*/+CI.getFrontendOpts().IncludeTimestamps);
}

bool GenerateHeaderUnitAction::BeginSourceFileAction(CompilerInstance &CI) {
if (!CI.getLangOpts().CPlusPlusModules) {
CI.getDiagnostics().Report(diag::err_module_interface_requires_cpp_modules);
Expand Down Expand Up @@ -839,7 +865,6 @@ void DumpModuleInfoAction::ExecuteAction() {

const LangOptions &LO = getCurrentASTUnit().getLangOpts();
if (LO.CPlusPlusModules && !LO.CurrentModule.empty()) {

ASTReader *R = getCurrentASTUnit().getASTReader().get();
unsigned SubModuleCount = R->getTotalNumSubmodules();
serialization::ModuleFile &MF = R->getModuleManager().getPrimaryModule();
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Frontend/InitPreprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -736,7 +736,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
}
// C++23 features.
if (LangOpts.CPlusPlus23) {
Builder.defineMacro("__cpp_implicit_move", "202011L");
Builder.defineMacro("__cpp_implicit_move", "202207L");
Builder.defineMacro("__cpp_size_t_suffix", "202011L");
Builder.defineMacro("__cpp_if_consteval", "202106L");
Builder.defineMacro("__cpp_multidimensional_subscript", "202211L");
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ CreateFrontendBaseAction(CompilerInstance &CI) {
return std::make_unique<GenerateModuleFromModuleMapAction>();
case GenerateModuleInterface:
return std::make_unique<GenerateModuleInterfaceAction>();
case GenerateReducedModuleInterface:
return std::make_unique<GenerateReducedModuleInterfaceAction>();
case GenerateHeaderUnit:
return std::make_unique<GenerateHeaderUnitAction>();
case GeneratePCH: return std::make_unique<GeneratePCHAction>();
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/InstallAPI/Frontend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ namespace clang::installapi {
GlobalRecord *FrontendRecordsSlice::addGlobal(
StringRef Name, RecordLinkage Linkage, GlobalRecord::Kind GV,
const clang::AvailabilityInfo Avail, const Decl *D, const HeaderType Access,
SymbolFlags Flags) {
SymbolFlags Flags, bool Inlined) {

auto *GR = llvm::MachO::RecordsSlice::addGlobal(Name, Linkage, GV, Flags);
auto *GR =
llvm::MachO::RecordsSlice::addGlobal(Name, Linkage, GV, Flags, Inlined);
FrontendRecords.insert({GR, FrontendAttrs{Avail, D, Access}});
return GR;
}
Expand Down
78 changes: 78 additions & 0 deletions clang/lib/InstallAPI/Visitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//

#include "clang/InstallAPI/Visitor.h"
#include "clang/AST/ParentMapContext.h"
#include "clang/Basic/Linkage.h"
#include "clang/InstallAPI/Frontend.h"
#include "llvm/ADT/SmallString.h"
Expand All @@ -27,6 +28,31 @@ static bool isExported(const NamedDecl *D) {
(LV.getVisibility() == DefaultVisibility);
}

static bool isInlined(const FunctionDecl *D) {
bool HasInlineAttribute = false;
bool NoCXXAttr =
(!D->getASTContext().getLangOpts().CPlusPlus &&
!D->getASTContext().getTargetInfo().getCXXABI().isMicrosoft() &&
!D->hasAttr<DLLExportAttr>());

// Check all redeclarations to find an inline attribute or keyword.
for (const auto *RD : D->redecls()) {
if (!RD->isInlined())
continue;
HasInlineAttribute = true;
if (!(NoCXXAttr || RD->hasAttr<GNUInlineAttr>()))
continue;
if (RD->doesThisDeclarationHaveABody() &&
RD->isInlineDefinitionExternallyVisible())
return false;
}

if (!HasInlineAttribute)
return false;

return true;
}

static SymbolFlags getFlags(bool WeakDef, bool ThreadLocal) {
SymbolFlags Result = SymbolFlags::None;
if (WeakDef)
Expand Down Expand Up @@ -204,4 +230,56 @@ bool InstallAPIVisitor::VisitVarDecl(const VarDecl *D) {
return true;
}

bool InstallAPIVisitor::VisitFunctionDecl(const FunctionDecl *D) {
if (const CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(D)) {
// Skip member function in class templates.
if (M->getParent()->getDescribedClassTemplate() != nullptr)
return true;

// Skip methods in CXX RecordDecls.
for (auto P : D->getASTContext().getParents(*M)) {
if (P.get<CXXRecordDecl>())
return true;
}

// Skip CXX ConstructorDecls and DestructorDecls.
if (isa<CXXConstructorDecl>(M) || isa<CXXDestructorDecl>(M))
return true;
}

// Skip templated functions.
switch (D->getTemplatedKind()) {
case FunctionDecl::TK_NonTemplate:
case FunctionDecl::TK_DependentNonTemplate:
break;
case FunctionDecl::TK_MemberSpecialization:
case FunctionDecl::TK_FunctionTemplateSpecialization:
if (auto *TempInfo = D->getTemplateSpecializationInfo()) {
if (!TempInfo->isExplicitInstantiationOrSpecialization())
return true;
}
break;
case FunctionDecl::TK_FunctionTemplate:
case FunctionDecl::TK_DependentFunctionTemplateSpecialization:
return true;
}

auto Access = getAccessForDecl(D);
if (!Access)
return true;
auto Name = getMangledName(D);
const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D);
const bool ExplicitInstantiation = D->getTemplateSpecializationKind() ==
TSK_ExplicitInstantiationDeclaration;
const bool WeakDef = ExplicitInstantiation || D->hasAttr<WeakAttr>();
const bool Inlined = isInlined(D);
const RecordLinkage Linkage = (Inlined || !isExported(D))
? RecordLinkage::Internal
: RecordLinkage::Exported;
Ctx.Slice->addGlobal(Name, Linkage, GlobalRecord::Kind::Function, Avail, D,
*Access, getFlags(WeakDef, /*ThreadLocal=*/false),
Inlined);
return true;
}

} // namespace clang::installapi
Loading