669 changes: 367 additions & 302 deletions clang-tools-extra/clangd/TidyFastChecks.inc

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ New check aliases
Changes in existing checks
^^^^^^^^^^^^^^^^^^^^^^^^^^

- Improved :doc:`bugprone-casting-through-void
<clang-tidy/checks/bugprone/casting-through-void>` check to suggest replacing
the offending code with ``reinterpret_cast``, to more clearly express intent.

- Improved :doc:`modernize-use-std-format
<clang-tidy/checks/modernize/use-std-format>` check to support replacing
member function calls too.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
bugprone-casting-through-void
=============================

Detects unsafe or redundant two-step casting operations involving ``void*``.
Detects unsafe or redundant two-step casting operations involving ``void*``,
which is equivalent to ``reinterpret_cast`` as per the
`C++ Standard <https://eel.is/c++draft/expr.reinterpret.cast#7>`_.

Two-step type conversions via ``void*`` are discouraged for several reasons.

Expand All @@ -16,7 +18,17 @@ Two-step type conversions via ``void*`` are discouraged for several reasons.

In summary, avoiding two-step type conversions through ``void*`` ensures clearer code,
maintains essential compiler warnings, and prevents ambiguity and potential runtime
errors, particularly in complex inheritance scenarios.
errors, particularly in complex inheritance scenarios. If such a cast is wanted,
it shall be done via ``reinterpret_cast``, to express the intent more clearly.

Note: it is expected that, after applying the suggested fix and using
``reinterpret_cast``, the check :doc:`cppcoreguidelines-pro-type-reinterpret-cast
<../cppcoreguidelines/pro-type-reinterpret-cast>` will emit a warning.
This is intentional: ``reinterpret_cast`` is a dangerous operation that can
easily break the strict aliasing rules when dereferencing the casted pointer,
invoking Undefined Behavior. The warning is there to prompt users to carefuly
analyze whether the usage of ``reinterpret_cast`` is safe, in which case the
warning may be suppressed.

Examples:

Expand All @@ -29,3 +41,8 @@ Examples:
reinterpret_cast<IntegerPointer>(reinterpret_cast<void *>(ptr)); // WRONG
(IntegerPointer)(void *)ptr; // WRONG
IntegerPointer(static_cast<void *>(ptr)); // WRONG
reinterpret_cast<IntegerPointer>(ptr); // OK, clearly expresses intent.
// NOTE: dereferencing this pointer violates
// the strict aliasing rules, invoking
// Undefined Behavior.
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ This check implements detection of local variables which could be declared as
``const`` but are not. Declaring variables as ``const`` is required or recommended by many
coding guidelines, such as:
`ES.25 <https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es25-declare-an-object-const-or-constexpr-unless-you-want-to-modify-its-value-later-on>`_
from the C++ Core Guidelines and `AUTOSAR C++14 Rule A7-1-1 (6.7.1 Specifiers)
<https://www.autosar.org/fileadmin/standards/R22-11/AP/AUTOSAR_RS_CPP14Guidelines.pdf>`_.
from the C++ Core Guidelines.

Please note that this check's analysis is type-based only. Variables that are not modified
but used to create a non-const handle that might escape the scope are not diagnosed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,3 @@ types and definitions with good return type but wrong ``return`` statements.
type (e.g. ``int``).
* Private and deleted operators are ignored.
* The operator must always return ``*this``.

This check implements `AUTOSAR C++14 Rule A13-2-1
<https://www.autosar.org/fileadmin/standards/R22-11/AP/AUTOSAR_RS_CPP14Guidelines.pdf>`_.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,3 @@ Examples:
int NestInConditional = (condition1 ? true1 : false1) ? true2 : false2;
int NestInTrue = condition1 ? (condition2 ? true1 : false1) : false2;
int NestInFalse = condition1 ? true1 : condition2 ? true2 : false1;

This check implements part of `AUTOSAR C++14 Rule A5-16-1
<https://www.autosar.org/fileadmin/standards/R22-11/AP/AUTOSAR_RS_CPP14Guidelines.pdf>`_.
27 changes: 23 additions & 4 deletions clang-tools-extra/include-cleaner/lib/WalkAST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/TemplateName.h"
Expand All @@ -23,9 +24,11 @@
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/STLFunctionalExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"

namespace clang::include_cleaner {
namespace {
Expand Down Expand Up @@ -125,6 +128,24 @@ class ASTWalker : public RecursiveASTVisitor<ASTWalker> {
return true;
}

bool qualifierIsNamespaceOrNone(DeclRefExpr *DRE) {
const auto *Qual = DRE->getQualifier();
if (!Qual)
return true;
switch (Qual->getKind()) {
case NestedNameSpecifier::Namespace:
case NestedNameSpecifier::NamespaceAlias:
case NestedNameSpecifier::Global:
return true;
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
case NestedNameSpecifier::Super:
case NestedNameSpecifier::Identifier:
return false;
}
llvm_unreachable("Unknown value for NestedNameSpecifierKind");
}

bool VisitDeclRefExpr(DeclRefExpr *DRE) {
auto *FD = DRE->getFoundDecl();
// Prefer the underlying decl if FoundDecl isn't a shadow decl, e.g:
Expand All @@ -146,10 +167,8 @@ class ASTWalker : public RecursiveASTVisitor<ASTWalker> {
//
// If it's an enum constant, it must be due to prior decl. Report references
// to it when qualifier isn't a type.
if (llvm::isa<EnumConstantDecl>(FD)) {
if (!DRE->getQualifier() || DRE->getQualifier()->getAsNamespace())
report(DRE->getLocation(), FD);
}
if (llvm::isa<EnumConstantDecl>(FD) && qualifierIsNamespaceOrNone(DRE))
report(DRE->getLocation(), FD);
return true;
}

Expand Down
3 changes: 3 additions & 0 deletions clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,9 @@ TEST(WalkAST, Enums) {
testWalk(R"(namespace ns { enum E { A = 42 }; }
struct S { using ns::E::A; };)",
"int e = S::^A;");
testWalk(R"(namespace ns { enum E { $explicit^A = 42 }; })",
"namespace z = ns; int e = z::^A;");
testWalk(R"(enum E { $explicit^A = 42 };)", "int e = ::^A;");
}

TEST(WalkAST, InitializerList) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,54 +10,54 @@ const double cd = 100;

void normal_test() {
static_cast<int *>(static_cast<void *>(&d));
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void *' [bugprone-casting-through-void]
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void *'; use reinterpret_cast instead [bugprone-casting-through-void]
static_cast<int *>(static_cast<V>(&d));
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'V' (aka 'void *') [bugprone-casting-through-void]
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'V' (aka 'void *'); use reinterpret_cast instead [bugprone-casting-through-void]
static_cast<int *>(static_cast<void *>(&i));
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'int *' to 'int *' through 'void *' [bugprone-casting-through-void]
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'int *' to 'int *' through 'void *'; use reinterpret_cast instead [bugprone-casting-through-void]

static_cast<void *>(static_cast<void *>(&i));
}

void const_pointer_test() {
static_cast<int *const>(static_cast<void *>(&d));
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not cast 'double *' to 'int *const' through 'void *' [bugprone-casting-through-void]
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not cast 'double *' to 'int *const' through 'void *'; use reinterpret_cast instead [bugprone-casting-through-void]
static_cast<int *const>(static_cast<V>(&d));
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not cast 'double *' to 'int *const' through 'V' (aka 'void *') [bugprone-casting-through-void]
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not cast 'double *' to 'int *const' through 'V' (aka 'void *'); use reinterpret_cast instead [bugprone-casting-through-void]
static_cast<int *const>(static_cast<void *>(&i));
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not cast 'int *' to 'int *const' through 'void *' [bugprone-casting-through-void]
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not cast 'int *' to 'int *const' through 'void *'; use reinterpret_cast instead [bugprone-casting-through-void]

static_cast<void *const>(static_cast<void *>(&i));
}

void const_test() {
static_cast<const int *>(static_cast<const void *>(&d));
// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'double *' to 'const int *' through 'const void *' [bugprone-casting-through-void]
// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'double *' to 'const int *' through 'const void *'; use reinterpret_cast instead [bugprone-casting-through-void]
static_cast<const int *>(static_cast<const V>(&d));
// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'double *' to 'const int *' through 'const V' (aka 'void *const') [bugprone-casting-through-void]
// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'double *' to 'const int *' through 'const V' (aka 'void *const'); use reinterpret_cast instead [bugprone-casting-through-void]
static_cast<const int *>(static_cast<const void *>(&i));
// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'int *' to 'const int *' through 'const void *' [bugprone-casting-through-void]
// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'int *' to 'const int *' through 'const void *'; use reinterpret_cast instead [bugprone-casting-through-void]

static_cast<const void *>(static_cast<const void *>(&i));

static_cast<const int *>(static_cast<const void *>(&cd));
// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'const double *' to 'const int *' through 'const void *' [bugprone-casting-through-void]
// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'const double *' to 'const int *' through 'const void *'; use reinterpret_cast instead [bugprone-casting-through-void]
static_cast<const int *>(static_cast<const CV>(&cd));
// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'const double *' to 'const int *' through 'const CV' (aka 'const void *const') [bugprone-casting-through-void]
// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'const double *' to 'const int *' through 'const CV' (aka 'const void *const'); use reinterpret_cast instead [bugprone-casting-through-void]
static_cast<const int *>(static_cast<const void *>(&ci));
// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'const int *' to 'const int *' through 'const void *' [bugprone-casting-through-void]
// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'const int *' to 'const int *' through 'const void *'; use reinterpret_cast instead [bugprone-casting-through-void]

static_cast<const void *>(static_cast<const void *>(&ci));
}


void reinterpret_cast_test() {
static_cast<int *>(reinterpret_cast<void *>(&d));
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void *' [bugprone-casting-through-void]
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void *'; use reinterpret_cast instead [bugprone-casting-through-void]
reinterpret_cast<int *>(static_cast<void *>(&d));
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not cast 'double *' to 'int *' through 'void *' [bugprone-casting-through-void]
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not cast 'double *' to 'int *' through 'void *'; use reinterpret_cast instead [bugprone-casting-through-void]
reinterpret_cast<int *>(reinterpret_cast<void *>(&d));
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not cast 'double *' to 'int *' through 'void *' [bugprone-casting-through-void]
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not cast 'double *' to 'int *' through 'void *'; use reinterpret_cast instead [bugprone-casting-through-void]

static_cast<void *>(reinterpret_cast<void *>(&i));
reinterpret_cast<void *>(reinterpret_cast<void *>(&i));
Expand All @@ -66,11 +66,11 @@ void reinterpret_cast_test() {

void c_style_cast_test() {
static_cast<int *>((void *)&d);
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void *' [bugprone-casting-through-void]
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void *'; use reinterpret_cast instead [bugprone-casting-through-void]
(int *)(void *)&d;
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: do not cast 'double *' to 'int *' through 'void *' [bugprone-casting-through-void]
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: do not cast 'double *' to 'int *' through 'void *'; use reinterpret_cast instead [bugprone-casting-through-void]
static_cast<int *>((void *)&d);
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void *' [bugprone-casting-through-void]
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void *'; use reinterpret_cast instead [bugprone-casting-through-void]

static_cast<void *>((void *)&i);
}
Expand All @@ -82,12 +82,12 @@ using I = int *;
void cxx_functional_cast() {
A(static_cast<void*>(&d));
I(static_cast<void*>(&d));
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not cast 'double *' to 'I' (aka 'int *') through 'void *' [bugprone-casting-through-void]
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not cast 'double *' to 'I' (aka 'int *') through 'void *'; use reinterpret_cast instead [bugprone-casting-through-void]
}

void bit_cast() {
__builtin_bit_cast(int *, static_cast<void *>(&d));
// CHECK-MESSAGES: :[[@LINE-1]]:29: warning: do not cast 'double *' to 'int *' through 'void *' [bugprone-casting-through-void]
// CHECK-MESSAGES: :[[@LINE-1]]:29: warning: do not cast 'double *' to 'int *' through 'void *'; use reinterpret_cast instead [bugprone-casting-through-void]
}

namespace PR87069 {
Expand Down
2 changes: 2 additions & 0 deletions clang/cmake/caches/Fuchsia-stage2.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ foreach(target aarch64-unknown-linux-gnu;armv7-unknown-linux-gnueabihf;i386-unkn
set(BUILTINS_${target}_CMAKE_MODULE_LINKER_FLAGS "-fuse-ld=lld" CACHE STRING "")
set(BUILTINS_${target}_CMAKE_EXE_LINKER_FLAG "-fuse-ld=lld" CACHE STRING "")
set(BUILTINS_${target}_COMPILER_RT_BUILD_STANDALONE_LIBATOMIC ON CACHE BOOL "")
set(BUILTINS_${target}_COMPILER_RT_LIBATOMIC_USE_PTHREAD ON CACHE BOOL "")

# Set the per-target runtimes options.
list(APPEND RUNTIME_TARGETS "${target}")
Expand All @@ -169,6 +170,7 @@ foreach(target aarch64-unknown-linux-gnu;armv7-unknown-linux-gnueabihf;i386-unkn
set(RUNTIMES_${target}_CMAKE_EXE_LINKER_FLAGS "-fuse-ld=lld" CACHE STRING "")
set(RUNTIMES_${target}_COMPILER_RT_CXX_LIBRARY "libcxx" CACHE STRING "")
set(RUNTIMES_${target}_COMPILER_RT_USE_BUILTINS_LIBRARY ON CACHE BOOL "")
set(RUNTIMES_${target}_COMPILER_RT_USE_ATOMIC_LIBRARY ON CACHE BOOL "")
set(RUNTIMES_${target}_COMPILER_RT_USE_LLVM_UNWINDER ON CACHE BOOL "")
set(RUNTIMES_${target}_COMPILER_RT_CAN_EXECUTE_TESTS ON CACHE BOOL "")
set(RUNTIMES_${target}_COMPILER_RT_BUILD_STANDALONE_LIBATOMIC ON CACHE BOOL "")
Expand Down
12 changes: 10 additions & 2 deletions clang/cmake/caches/Release.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,22 @@ set(STAGE1_RUNTIMES "compiler-rt")

if (LLVM_RELEASE_ENABLE_PGO)
list(APPEND STAGE1_PROJECTS "lld")
set(CLANG_BOOTSTRAP_TARGETS
set(tmp_targets
generate-profdata
stage2-package
stage2-clang
stage2
stage2-install
stage2-check-all
stage2-check-llvm
stage2-check-clang CACHE STRING "")
stage2-check-clang)

foreach(X IN LISTS LLVM_RELEASE_FINAL_STAGE_TARGETS)
list(APPEND tmp_targets "stage2-${X}")
endforeach()
list(REMOVE_DUPLICATES tmp_targets)

set(CLANG_BOOTSTRAP_TARGETS "${tmp_targets}" CACHE STRING "")

# Configuration for stage2-instrumented
set(BOOTSTRAP_CLANG_ENABLE_BOOTSTRAP ON CACHE STRING "")
Expand Down
2 changes: 2 additions & 0 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1483,6 +1483,7 @@ Generic lambda expressions __cpp_generic_lambdas C+
variable templates __cpp_variable_templates C++14 C++03
Binary literals __cpp_binary_literals C++14 C++03
Relaxed constexpr __cpp_constexpr C++14 C++11
Static assert with no message __cpp_static_assert >= 201411L C++17 C++11
Pack expansion in generalized lambda-capture __cpp_init_captures C++17 C++03
``if constexpr`` __cpp_if_constexpr C++17 C++11
fold expressions __cpp_fold_expressions C++17 C++03
Expand All @@ -1503,6 +1504,7 @@ Conditional ``explicit`` __cpp_conditional_explicit C+
``static operator()`` __cpp_static_call_operator C++23 C++03
Attributes on Lambda-Expressions C++23 C++11
Attributes on Structured Bindings __cpp_structured_bindings C++26 C++03
Static assert with user-generated message __cpp_static_assert >= 202306L C++26 C++11
Pack Indexing __cpp_pack_indexing C++26 C++03
``= delete ("should have a reason");`` __cpp_deleted_function C++26 C++03
Variadic Friends __cpp_variadic_friend C++26 C++03
Expand Down
6 changes: 6 additions & 0 deletions clang/docs/Multilib.rst
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,12 @@ For a more comprehensive example see
# to be a match.
Flags: [--target=thumbv7m-none-eabi, -mfpu=fpv4-sp-d16]
# If there is no multilib available for a particular set of flags, and the
# other multilibs are not adequate fallbacks, then you can define a variant
# record with a FatalError key in place of the Dir key.
- FatalError: this multilib collection has no hard-float ABI support
Flags: [--target=thumbv7m-none-eabi, -mfloat-abi=hard]
# The second section of the file is a list of regular expressions that are
# used to map from flags generated from command line options to custom flags.
Expand Down
31 changes: 31 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ C++ Language Changes
constant expression. Supports the `V.xyzw` syntax and other tidbits
as seen in OpenCL. Selecting multiple elements is left as a future work.

- Accept C++26 user-defined ``static_assert`` messages in C++11 as an extension.


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

Expand All @@ -122,6 +125,9 @@ C++2c Feature Support

- Implemented `P2747R2 constexpr placement new <https://wg21.link/P2747R2>`_.

- Added the ``__builtin_is_within_lifetime`` builtin, which supports
`P2641R4 Checking if a union alternative is active <https://wg21.link/p2641r4>`_

C++23 Feature Support
^^^^^^^^^^^^^^^^^^^^^
- Removed the restriction to literal types in constexpr functions in C++23 mode.
Expand Down Expand Up @@ -154,6 +160,10 @@ Resolutions to C++ Defect Reports
- Allow ``void{}`` as a prvalue of type ``void``.
(`CWG2351: void{} <https://cplusplus.github.io/CWG/issues/2351.html>`_).

- Clang now allows comparing unequal object pointers that have been cast to ``void *``
in constant expressions. These comparisons always worked in non-constant expressions.
(`CWG2749: Treatment of "pointer to void" for relational comparisons <https://cplusplus.github.io/CWG/issues/2749.html>`_).

C Language Changes
------------------

Expand Down Expand Up @@ -225,6 +235,11 @@ Attribute Changes in Clang
more cases where the returned reference outlives the object.
(#GH100567)

- Clang now correctly diagnoses the use of ``btf_type_tag`` in C++ and ignores
it; this attribute is a C-only attribute, and caused crashes with template
instantiation by accidentally allowing it in C++ in some circumstances.
(#GH106864)

Improvements to Clang's diagnostics
-----------------------------------

Expand Down Expand Up @@ -266,6 +281,15 @@ Improvements to Clang's diagnostics
compilation speed with modules. This warning is disabled by default and it needs
to be explicitly enabled or by ``-Weverything``.

- Improved diagnostic when trying to overload a function in an ``extern "C"`` context. (#GH80235)

- Clang now respects lifetimebound attribute for the assignment operator parameter. (#GH106372).

- The lifetimebound and GSL analysis in clang are coherent, allowing clang to
detect more use-after-free bugs. (#GH100549).

- Clang now warns for u8 character literals used in C23 with ``-Wpre-c23-compat`` instead of ``-Wpre-c++17-compat``.

Improvements to Clang's time-trace
----------------------------------

Expand Down Expand Up @@ -339,6 +363,13 @@ Bug Fixes to C++ Support
- Template parameter names are considered in the name lookup of out-of-line class template
specialization right before its declaration context. (#GH64082)
- Fixed a constraint comparison bug for friend declarations. (#GH78101)
- Fix handling of ``_`` as the name of a lambda's init capture variable. (#GH107024)
- Fix an issue with dependent source location expressions (#GH106428), (#GH81155), (#GH80210), (#GH85373)
- Fixed a bug in the substitution of empty pack indexing types. (#GH105903)
- Clang no longer tries to capture non-odr used default arguments of template parameters of generic lambdas (#GH107048)
- Fixed a bug where defaulted comparison operators would remove ``const`` from base classes. (#GH102588)

- Fix a crash when using ``source_location`` in the trailing return type of a lambda expression. (#GH67134)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
32 changes: 16 additions & 16 deletions clang/docs/analyzer/checkers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1293,6 +1293,22 @@ security.insecureAPI.DeprecatedOrUnsafeBufferHandling (C)
strncpy(buf, "a", 1); // warn
}
.. _security-MmapWriteExec:
security.MmapWriteExec (C)
""""""""""""""""""""""""""
Warn on ``mmap()`` calls with both writable and executable access.
.. code-block:: c
void test(int n) {
void *c = mmap(NULL, 32, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANON, -1, 0);
// warn: Both PROT_WRITE and PROT_EXEC flags are set. This can lead to
// exploitable memory regions, which could be overwritten with malicious
// code
}
.. _security-putenv-stack-array:
security.PutenvStackArray (C)
Expand Down Expand Up @@ -2967,22 +2983,6 @@ Warn about buffer overflows (newer checker).
char c = s[x]; // warn: index is tainted
}
.. _alpha-security-MmapWriteExec:
alpha.security.MmapWriteExec (C)
""""""""""""""""""""""""""""""""
Warn on mmap() calls that are both writable and executable.
.. code-block:: c
void test(int n) {
void *c = mmap(NULL, 32, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANON, -1, 0);
// warn: Both PROT_WRITE and PROT_EXEC flags are set. This can lead to
// exploitable memory regions, which could be overwritten with malicious
// code
}
.. _alpha-security-ReturnPtrRange:
alpha.security.ReturnPtrRange (C)
Expand Down
6 changes: 3 additions & 3 deletions clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -2722,9 +2722,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
const ObjCMethodDecl *MethodImp);

bool UnwrapSimilarTypes(QualType &T1, QualType &T2,
bool AllowPiMismatch = true);
bool AllowPiMismatch = true) const;
void UnwrapSimilarArrayTypes(QualType &T1, QualType &T2,
bool AllowPiMismatch = true);
bool AllowPiMismatch = true) const;

/// Determine if two types are similar, according to the C++ rules. That is,
/// determine if they are the same other than qualifiers on the initial
Expand All @@ -2733,7 +2733,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
///
/// Clang offers a number of qualifiers in addition to the C++ qualifiers;
/// those qualifiers are also ignored in the 'similarity' check.
bool hasSimilarType(QualType T1, QualType T2);
bool hasSimilarType(QualType T1, QualType T2) const;

/// Determine if two types are similar, ignoring only CVR qualifiers.
bool hasCvrSimilarType(QualType T1, QualType T2);
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/AST/CXXRecordDeclDefinitionBits.def
Original file line number Diff line number Diff line change
Expand Up @@ -249,4 +249,8 @@ FIELD(HasDeclaredCopyAssignmentWithConstParam, 1, MERGE_OR)
/// base classes or fields have a no-return destructor
FIELD(IsAnyDestructorNoReturn, 1, NO_MERGE)

/// Whether the record type is intangible (if any base classes or fields have
/// type that is intangible). HLSL only.
FIELD(IsHLSLIntangible, 1, NO_MERGE)

#undef FIELD
4 changes: 4 additions & 0 deletions clang/include/clang/AST/DeclCXX.h
Original file line number Diff line number Diff line change
Expand Up @@ -1547,6 +1547,10 @@ class CXXRecordDecl : public RecordDecl {
/// destructors are marked noreturn.
bool isAnyDestructorNoReturn() const { return data().IsAnyDestructorNoReturn; }

/// Returns true if the class contains HLSL intangible type, either as
/// a field or in base class.
bool isHLSLIntangible() const { return data().IsHLSLIntangible; }

/// If the class is a local class [class.local], returns
/// the enclosing function declaration.
const FunctionDecl *isLocalClass() const {
Expand Down
20 changes: 16 additions & 4 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -2658,6 +2658,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) bool is##Id##Type() const;
#include "clang/Basic/HLSLIntangibleTypes.def"
bool isHLSLSpecificType() const; // Any HLSL specific type
bool isHLSLIntangibleType() const; // Any HLSL intangible type

/// Determines if this type, which must satisfy
/// isObjCLifetimeType(), is implicitly __unsafe_unretained rather
Expand Down Expand Up @@ -5828,12 +5829,15 @@ class PackIndexingType final
QualType Pattern;
Expr *IndexExpr;

unsigned Size;
unsigned Size : 31;

LLVM_PREFERRED_TYPE(bool)
unsigned ExpandsToEmptyPack : 1;

protected:
friend class ASTContext; // ASTContext creates these.
PackIndexingType(const ASTContext &Context, QualType Canonical,
QualType Pattern, Expr *IndexExpr,
QualType Pattern, Expr *IndexExpr, bool ExpandsToEmptyPack,
ArrayRef<QualType> Expansions = {});

public:
Expand All @@ -5857,6 +5861,8 @@ class PackIndexingType final

bool hasSelectedType() const { return getSelectedIndex() != std::nullopt; }

bool expandsToEmptyPack() const { return ExpandsToEmptyPack; }

ArrayRef<QualType> getExpansions() const {
return {getExpansionsPtr(), Size};
}
Expand All @@ -5869,10 +5875,10 @@ class PackIndexingType final
if (hasSelectedType())
getSelectedType().Profile(ID);
else
Profile(ID, Context, getPattern(), getIndexExpr());
Profile(ID, Context, getPattern(), getIndexExpr(), expandsToEmptyPack());
}
static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
QualType Pattern, Expr *E);
QualType Pattern, Expr *E, bool ExpandsToEmptyPack);

private:
const QualType *getExpansionsPtr() const {
Expand Down Expand Up @@ -8336,6 +8342,12 @@ inline bool Type::isHLSLSpecificType() const {
false; // end boolean or operation
}

inline bool Type::isHLSLIntangibleType() const {
// All HLSL specific types are currently intangible type as well, but that
// might change in the future.
return isHLSLSpecificType();
}

inline bool Type::isTemplateTypeParmType() const {
return isa<TemplateTypeParmType>(CanonicalType);
}
Expand Down
8 changes: 8 additions & 0 deletions clang/include/clang/AST/TypeLoc.h
Original file line number Diff line number Diff line change
Expand Up @@ -951,12 +951,20 @@ class HLSLAttributedResourceTypeLoc
HLSLAttributedResourceLocInfo> {
public:
TypeLoc getWrappedLoc() const { return getInnerTypeLoc(); }

TypeLoc getContainedLoc() const {
return TypeLoc(getTypePtr()->getContainedType(), getNonLocalData());
}

void setSourceRange(const SourceRange &R) { getLocalData()->Range = R; }
SourceRange getLocalSourceRange() const { return getLocalData()->Range; }
void initializeLocal(ASTContext &Context, SourceLocation loc) {
setSourceRange(SourceRange());
}
QualType getInnerType() const { return getTypePtr()->getWrappedType(); }
unsigned getLocalDataSize() const {
return sizeof(HLSLAttributedResourceLocInfo);
}
};

struct ObjCObjectTypeLocInfo {
Expand Down
5 changes: 4 additions & 1 deletion clang/include/clang/AST/TypeProperties.td
Original file line number Diff line number Diff line change
Expand Up @@ -473,9 +473,12 @@ let Class = PackIndexingType in {
def : Property<"indexExpression", ExprRef> {
let Read = [{ node->getIndexExpr() }];
}
def : Property<"expandsToEmptyPack", Bool> {
let Read = [{ node->expandsToEmptyPack() }];
}

def : Creator<[{
return ctx.getPackIndexingType(pattern, indexExpression);
return ctx.getPackIndexingType(pattern, indexExpression, expandsToEmptyPack);
}]>;
}

Expand Down
19 changes: 19 additions & 0 deletions clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#define LLVM_CLANG_ANALYSIS_ANALYSES_UNSAFEBUFFERUSAGE_H

#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Stmt.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/Support/Debug.h"
Expand Down Expand Up @@ -106,6 +107,20 @@ class UnsafeBufferUsageHandler {
virtual void handleUnsafeOperation(const Stmt *Operation,
bool IsRelatedToDecl, ASTContext &Ctx) = 0;

/// Invoked when a call to an unsafe libc function is found.
/// \param PrintfInfo
/// is 0 if the callee function is not a member of the printf family;
/// is 1 if the callee is `sprintf`;
/// is 2 if arguments of the call have `__size_by` relation but are not in a
/// safe pattern;
/// is 3 if string arguments do not guarantee null-termination
/// is 4 if the callee takes va_list
/// \param UnsafeArg one of the actual arguments that is unsafe, non-null
/// only when `2 <= PrintfInfo <= 3`
virtual void handleUnsafeLibcCall(const CallExpr *Call, unsigned PrintfInfo,
ASTContext &Ctx,
const Expr *UnsafeArg = nullptr) = 0;

/// Invoked when an unsafe operation with a std container is found.
virtual void handleUnsafeOperationInContainer(const Stmt *Operation,
bool IsRelatedToDecl,
Expand Down Expand Up @@ -151,6 +166,10 @@ class UnsafeBufferUsageHandler {
virtual bool
ignoreUnsafeBufferInContainer(const SourceLocation &Loc) const = 0;

/// \return true iff unsafe libc call should NOT be reported at `Loc`
virtual bool
ignoreUnsafeBufferInLibcCall(const SourceLocation &Loc) const = 0;

virtual std::string
getUnsafeBufferUsageAttributeTextAt(SourceLocation Loc,
StringRef WSSuffix = "") const = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@
#define WARNING_GADGET(name) GADGET(name)
#endif

/// A `WARNING_GADGET` subset, where the code pattern of each gadget
/// corresponds uses of a (possibly hardened) contatiner (e.g., `std::span`).
#ifndef WARNING_CONTAINER_GADGET
#define WARNING_CONTAINER_GADGET(name) WARNING_GADGET(name)
/// A `WARNING_GADGET` subset, each of which may be enable/disable separately
/// with different flags
#ifndef WARNING_OPTIONAL_GADGET
#define WARNING_OPTIONAL_GADGET(name) WARNING_GADGET(name)
#endif

/// Safe gadgets correspond to code patterns that aren't unsafe but need to be
Expand All @@ -38,7 +38,8 @@ WARNING_GADGET(PointerArithmetic)
WARNING_GADGET(UnsafeBufferUsageAttr)
WARNING_GADGET(UnsafeBufferUsageCtorAttr)
WARNING_GADGET(DataInvocation)
WARNING_CONTAINER_GADGET(SpanTwoParamConstructor) // Uses of `std::span(arg0, arg1)`
WARNING_OPTIONAL_GADGET(UnsafeLibcFunctionCall)
WARNING_OPTIONAL_GADGET(SpanTwoParamConstructor) // Uses of `std::span(arg0, arg1)`
FIXABLE_GADGET(ULCArraySubscript) // `DRE[any]` in an Unspecified Lvalue Context
FIXABLE_GADGET(DerefSimplePtrArithFixable)
FIXABLE_GADGET(PointerDereference)
Expand All @@ -52,5 +53,5 @@ FIXABLE_GADGET(PointerInit)

#undef FIXABLE_GADGET
#undef WARNING_GADGET
#undef WARNING_CONTAINER_GADGET
#undef WARNING_OPTIONAL_GADGET
#undef GADGET
36 changes: 32 additions & 4 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -1073,6 +1073,36 @@ static llvm::StringRef canonicalizePlatformName(llvm::StringRef Platform) {
.Case("ShaderModel", "shadermodel")
.Default(Platform);
}
static std::vector<llvm::StringRef> equivalentPlatformNames(llvm::StringRef Platform) {
return llvm::StringSwitch<std::vector<llvm::StringRef>>(Platform)
.Case("ios", {"ios", "iOS"})
.Case("iOS", {"ios", "iOS"})
.Case("macos", {"macos", "macOS"})
.Case("macOS", {"macos", "macOS"})
.Case("tvos", {"tvos", "tvOS"})
.Case("tvOS", {"tvos", "tvOS"})
.Case("watchos", {"watchos", "watchOS"})
.Case("watchOS", {"watchos", "watchOS"})
.Case("ios_app_extension", {"iOSApplicationExtension", "ios_app_extension"})
.Case("iOSApplicationExtension", {"iOSApplicationExtension", "ios_app_extension"})
.Case("macos_app_extension", {"macOSApplicationExtension", "macos_app_extension"})
.Case("macOSApplicationExtension", {"macOSApplicationExtension", "macos_app_extension"})
.Case("tvos_app_extension", {"tvOSApplicationExtension", "tvos_app_extension"})
.Case("tvOSApplicationExtension", {"tvOSApplicationExtension", "tvos_app_extension"})
.Case("watchos_app_extension", {"watchOSApplicationExtension", "watchos_app_extension"})
.Case("watchOSApplicationExtension", {"watchOSApplicationExtension", "watchos_app_extension"})
.Case("maccatalyst", {"macCatalyst", "maccatalyst"})
.Case("macCatalyst", {"macCatalyst", "maccatalyst"})
.Case("maccatalyst_app_extension", {"macCatalystApplicationExtension", "maccatalyst_app_extension"})
.Case("macCatalystApplicationExtension", {"macCatalystApplicationExtension", "maccatalyst_app_extension"})
.Case("xros", {"visionos", "visionOS", "xros"})
.Case("visionOS", {"visionos", "visionOS", "xros"})
.Case("visionos", {"visionos", "visionOS", "xros"})
.Case("xros_app_extension", {"visionOSApplicationExtension", "visionos_app_extension", "xros_app_extension"})
.Case("visionOSApplicationExtension", {"visionOSApplicationExtension", "visionos_app_extension", "xros_app_extension"})
.Case("visionos_app_extension", {"visionOSApplicationExtension", "visionos_app_extension", "xros_app_extension"})
.Default({Platform});
}
static llvm::Triple::EnvironmentType getEnvironmentType(llvm::StringRef Environment) {
return llvm::StringSwitch<llvm::Triple::EnvironmentType>(Environment)
.Case("pixel", llvm::Triple::Pixel)
Expand Down Expand Up @@ -4613,16 +4643,14 @@ def HLSLResource : InheritableAttr {
let Documentation = [InternalOnly];
}

def HLSLROV : InheritableAttr {
def HLSLROV : TypeAttr {
let Spellings = [CXX11<"hlsl", "is_rov">];
let Subjects = SubjectList<[Struct]>;
let LangOpts = [HLSL];
let Documentation = [InternalOnly];
}

def HLSLResourceClass : InheritableAttr {
def HLSLResourceClass : TypeAttr {
let Spellings = [CXX11<"hlsl", "resource_class">];
let Subjects = SubjectList<[Field]>;
let LangOpts = [HLSL];
let Args = [
EnumArgument<"ResourceClass", "llvm::hlsl::ResourceClass",
Expand Down
12 changes: 12 additions & 0 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -934,6 +934,12 @@ def IsConstantEvaluated : LangBuiltin<"CXX_LANG"> {
let Prototype = "bool()";
}

def IsWithinLifetime : LangBuiltin<"CXX_LANG"> {
let Spellings = ["__builtin_is_within_lifetime"];
let Attributes = [NoThrow, CustomTypeChecking, Consteval];
let Prototype = "bool(void*)";
}

// GCC exception builtins
def EHReturn : Builtin {
let Spellings = ["__builtin_eh_return"];
Expand Down Expand Up @@ -4679,6 +4685,12 @@ def HLSLWaveGetLaneIndex : LangBuiltin<"HLSL_LANG"> {
let Prototype = "unsigned int()";
}

def HLSLWaveIsFirstLane : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_wave_is_first_lane"];
let Attributes = [NoThrow, Const];
let Prototype = "bool()";
}

def HLSLClamp : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_elementwise_clamp"];
let Attributes = [NoThrow, Const];
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/BuiltinsAMDGPU.def
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,7 @@ TARGET_BUILTIN(__builtin_amdgcn_s_barrier_join, "vi", "n", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_wakeup_barrier, "vi", "n", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_barrier_leave, "b", "n", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_get_barrier_state, "Uii", "n", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_prefetch_data, "vvC*Ui", "nc", "gfx12-insts")

TARGET_BUILTIN(__builtin_amdgcn_global_load_tr_b64_v2i32, "V2iV2i*1", "nc", "gfx12-insts,wavefrontsize32")
TARGET_BUILTIN(__builtin_amdgcn_global_load_tr_b128_v8i16, "V8sV8s*1", "nc", "gfx12-insts,wavefrontsize32")
Expand Down
62 changes: 62 additions & 0 deletions clang/include/clang/Basic/BuiltinsX86.def
Original file line number Diff line number Diff line change
Expand Up @@ -2261,6 +2261,68 @@ TARGET_BUILTIN(__builtin_ia32_vcvtneph2hf8_512_mask, "V32cV32xV32cUi", "nV:512:"
TARGET_BUILTIN(__builtin_ia32_vcvtneph2hf8s_128_mask, "V16cV8xV16cUc", "nV:128:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vcvtneph2hf8s_256_mask, "V16cV16xV16cUs", "nV:256:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vcvtneph2hf8s_512_mask, "V32cV32xV32cUi", "nV:512:", "avx10.2-512")

// AVX10.2 BF16
TARGET_BUILTIN(__builtin_ia32_loadsbf16128_mask, "V8yV8yC*V8yUc", "nV:128:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_storesbf16128_mask, "vV8y*V8yUc", "nV:128:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vaddnepbf16128, "V8yV8yV8y", "ncV:128:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vaddnepbf16256, "V16yV16yV16y", "ncV:256:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vaddnepbf16512, "V32yV32yV32y", "ncV:512:", "avx10.2-512")
TARGET_BUILTIN(__builtin_ia32_vdivnepbf16128, "V8yV8yV8y", "ncV:128:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vdivnepbf16256, "V16yV16yV16y", "ncV:256:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vdivnepbf16512, "V32yV32yV32y", "ncV:512:", "avx10.2-512")
TARGET_BUILTIN(__builtin_ia32_vmaxpbf16128, "V8yV8yV8y", "ncV:128:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vmaxpbf16256, "V16yV16yV16y", "ncV:256:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vmaxpbf16512, "V32yV32yV32y", "ncV:512:", "avx10.2-512")
TARGET_BUILTIN(__builtin_ia32_vminpbf16128, "V8yV8yV8y", "ncV:128:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vminpbf16256, "V16yV16yV16y", "ncV:256:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vminpbf16512, "V32yV32yV32y", "ncV:512:", "avx10.2-512")
TARGET_BUILTIN(__builtin_ia32_vmulnepbf16128, "V8yV8yV8y", "ncV:128:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vmulnepbf16256, "V16yV16yV16y", "ncV:256:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vmulnepbf16512, "V32yV32yV32y", "ncV:512:", "avx10.2-512")
TARGET_BUILTIN(__builtin_ia32_vsubnepbf16128, "V8yV8yV8y", "ncV:128:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vsubnepbf16256, "V16yV16yV16y", "ncV:256:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vsubnepbf16512, "V32yV32yV32y", "ncV:512:", "avx10.2-512")
TARGET_BUILTIN(__builtin_ia32_vcomsbf16eq, "iV8yV8y", "ncV:128:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vcomsbf16lt, "iV8yV8y", "ncV:128:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vcomsbf16neq, "iV8yV8y", "ncV:128:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vcomsbf16ge, "iV8yV8y", "ncV:128:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vcomsbf16gt, "iV8yV8y", "ncV:128:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vcomsbf16le, "iV8yV8y", "ncV:128:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vcmppbf16512_mask,"UiV32yV32yIiUi", "ncV:512:", "avx10.2-512")
TARGET_BUILTIN(__builtin_ia32_vcmppbf16256_mask,"UsV16yV16yIiUs", "ncV:256:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vcmppbf16128_mask,"UcV8yV8yIiUc", "ncV:128:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vfpclasspbf16128_mask, "UcV8yIiUc", "ncV:128:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vfpclasspbf16256_mask, "UsV16yIiUs", "ncV:256:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vfpclasspbf16512_mask, "UiV32yIiUi", "ncV:512:", "avx10.2-512")
TARGET_BUILTIN(__builtin_ia32_vscalefpbf16128_mask, "V8yV8yV8yV8yUc", "ncV:128:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vscalefpbf16256_mask, "V16yV16yV16yV16yUs", "ncV:256:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vscalefpbf16512_mask, "V32yV32yV32yV32yUi", "ncV:512:", "avx10.2-512")
TARGET_BUILTIN(__builtin_ia32_vrcppbf16128_mask, "V8yV8yV8yUc", "ncV:128:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vrcppbf16256_mask, "V16yV16yV16yUs", "ncV:256:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vrcppbf16512_mask, "V32yV32yV32yUi", "ncV:512:", "avx10.2-512")
TARGET_BUILTIN(__builtin_ia32_vgetexppbf16128_mask, "V8yV8yV8yUc", "ncV:128:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vgetexppbf16256_mask, "V16yV16yV16yUs", "ncV:256:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vgetexppbf16512_mask, "V32yV32yV32yUi", "ncV:512:", "avx10.2-512")
TARGET_BUILTIN(__builtin_ia32_vrsqrtpbf16128_mask, "V8yV8yV8yUc", "ncV:128:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vrsqrtpbf16256_mask, "V16yV16yV16yUs", "ncV:256:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vrsqrtpbf16512_mask, "V32yV32yV32yUi", "ncV:512:", "avx10.2-512")
TARGET_BUILTIN(__builtin_ia32_vreducenepbf16128_mask, "V8yV8yIiV8yUc", "ncV:128:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vreducenepbf16256_mask, "V16yV16yIiV16yUs", "ncV:256:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vreducenepbf16512_mask, "V32yV32yIiV32yUi", "ncV:512:", "avx10.2-512")
TARGET_BUILTIN(__builtin_ia32_vrndscalenepbf16_128_mask, "V8yV8yIiV8yUc", "ncV:128:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vrndscalenepbf16_256_mask, "V16yV16yIiV16yUs", "ncV:256:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vrndscalenepbf16_mask, "V32yV32yIiV32yUi", "ncV:512:", "avx10.2-512")
TARGET_BUILTIN(__builtin_ia32_vgetmantpbf16128_mask, "V8yV8yIiV8yUc", "ncV:128:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vgetmantpbf16256_mask, "V16yV16yIiV16yUs", "ncV:256:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vgetmantpbf16512_mask, "V32yV32yIiV32yUi", "ncV:512:", "avx10.2-512")
TARGET_BUILTIN(__builtin_ia32_vsqrtnepbf16, "V8yV8y", "ncV:128:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vsqrtnepbf16256, "V16yV16y", "ncV:256:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vsqrtnepbf16512, "V32yV32y", "ncV:512:", "avx10.2-512")
TARGET_BUILTIN(__builtin_ia32_vfmaddnepbh512, "V32yV32yV32yV32y", "ncV:512:", "avx10.2-512")
TARGET_BUILTIN(__builtin_ia32_vfmaddnepbh256, "V16yV16yV16yV16y", "ncV:256:", "avx10.2-256")
TARGET_BUILTIN(__builtin_ia32_vfmaddnepbh128, "V8yV8yV8yV8y", "ncV:128:", "avx10.2-256")

#undef BUILTIN
#undef TARGET_BUILTIN
#undef TARGET_HEADER_BUILTIN
14 changes: 9 additions & 5 deletions clang/include/clang/Basic/DiagnosticASTKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,6 @@ def note_constexpr_var_init_weak : Note<
def note_constexpr_typeid_polymorphic : Note<
"typeid applied to expression of polymorphic type %0 is "
"not allowed in a constant expression in C++ standards before C++20">;
def note_constexpr_void_comparison : Note<
"comparison between unequal pointers to void has unspecified result">;
def note_constexpr_temporary_here : Note<"temporary created here">;
def note_constexpr_dynamic_alloc_here : Note<"heap allocation performed here">;
def note_constexpr_conditional_never_const : Note<
Expand All @@ -169,14 +167,14 @@ def note_constexpr_this : Note<
def access_kind : TextSubstitution<
"%select{read of|read of|assignment to|increment of|decrement of|"
"member call on|dynamic_cast of|typeid applied to|construction of|"
"destruction of}0">;
"destruction of|read of}0">;
def access_kind_subobject : TextSubstitution<
"%select{read of|read of|assignment to|increment of|decrement of|"
"member call on|dynamic_cast of|typeid applied to|"
"construction of subobject of|destruction of}0">;
"construction of subobject of|destruction of|read of}0">;
def access_kind_volatile : TextSubstitution<
"%select{read of|read of|assignment to|increment of|decrement of|"
"<ERROR>|<ERROR>|<ERROR>|<ERROR>|<ERROR>}0">;
"<ERROR>|<ERROR>|<ERROR>|<ERROR>|<ERROR>|<ERROR>}0">;
def note_constexpr_lifetime_ended : Note<
"%sub{access_kind}0 %select{temporary|variable}1 whose "
"%plural{8:storage duration|:lifetime}0 has ended">;
Expand Down Expand Up @@ -409,6 +407,12 @@ def warn_is_constant_evaluated_always_true_constexpr : Warning<
"'%0' will always evaluate to 'true' in a manifestly constant-evaluated expression">,
InGroup<DiagGroup<"constant-evaluated">>;

def err_invalid_is_within_lifetime : Note<
"'%0' cannot be called with "
"%select{a null pointer|a one-past-the-end pointer|"
"a pointer to an object whose lifetime has not yet begun}1"
>;

// inline asm related.
let CategoryName = "Inline Assembly Issue" in {
def err_asm_invalid_escape : Error<
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticDriverKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -810,6 +810,8 @@ def warn_drv_missing_multilib : Warning<
InGroup<DiagGroup<"missing-multilib">>;
def note_drv_available_multilibs : Note<
"available multilibs are:%0">;
def err_drv_multilib_custom_error : Error<
"multilib configuration error: %0">;

def err_drv_experimental_crel : Error<
"-Wa,--allow-experimental-crel must be specified to use -Wa,--crel. "
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Basic/DiagnosticGroups.td
Original file line number Diff line number Diff line change
Expand Up @@ -1558,7 +1558,8 @@ def ReadOnlyPlacementChecks : DiagGroup<"read-only-types">;

// Warnings and fixes to support the "safe buffers" programming model.
def UnsafeBufferUsageInContainer : DiagGroup<"unsafe-buffer-usage-in-container">;
def UnsafeBufferUsage : DiagGroup<"unsafe-buffer-usage", [UnsafeBufferUsageInContainer]>;
def UnsafeBufferUsageInLibcCall : DiagGroup<"unsafe-buffer-usage-in-libc-call">;
def UnsafeBufferUsage : DiagGroup<"unsafe-buffer-usage", [UnsafeBufferUsageInContainer, UnsafeBufferUsageInLibcCall]>;

// Warnings and notes related to the function effects system underlying
// the nonblocking and nonallocating attributes.
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/DiagnosticIDs.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ namespace clang {
DIAG_SIZE_AST = 300,
DIAG_SIZE_COMMENT = 100,
DIAG_SIZE_CROSSTU = 100,
DIAG_SIZE_SEMA = 4500,
DIAG_SIZE_SEMA = 5000,
DIAG_SIZE_ANALYSIS = 100,
DIAG_SIZE_REFACTORING = 1000,
DIAG_SIZE_INSTALLAPI = 100,
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticLexKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,9 @@ def warn_cxx98_compat_unicode_literal : Warning<
def warn_cxx14_compat_u8_character_literal : Warning<
"unicode literals are incompatible with C++ standards before C++17">,
InGroup<CXXPre17Compat>, DefaultIgnore;
def warn_c17_compat_u8_character_literal : Warning<
"unicode literals are incompatible with C standards before C23">,
InGroup<CPre23Compat>, DefaultIgnore;
def warn_cxx11_compat_user_defined_literal : Warning<
"identifier after literal will be treated as a user-defined literal suffix "
"in C++11">, InGroup<CXX11Compat>, DefaultIgnore;
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,12 @@ def warn_c17_compat_static_assert_no_message : Warning<
"'_Static_assert' with no message is incompatible with C standards before "
"C23">,
DefaultIgnore, InGroup<CPre23Compat>;
def ext_cxx_static_assert_user_generated_message : ExtWarn<
"'static_assert' with a user-generated message is a C++26 extension">,
InGroup<CXX26>;
def warn_cxx20_compat_static_assert_user_generated_message : Warning<
"'static_assert' with a user-generated message is incompatible with "
"C++ standards before C++26">, DefaultIgnore, InGroup<CXXPre26Compat>;
def err_function_definition_not_allowed : Error<
"function definition is not allowed here">;
def err_expected_end_of_enumerator : Error<
Expand Down
12 changes: 12 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -12186,6 +12186,10 @@ def err_builtin_launder_invalid_arg : Error<
"%select{non-pointer|function pointer|void pointer}0 argument to "
"'__builtin_launder' is not allowed">;

def err_builtin_is_within_lifetime_invalid_arg : Error<
"%select{non-|function }0pointer argument to '__builtin_is_within_lifetime' "
"is not allowed">;

def err_builtin_invalid_arg_type: Error <
"%ordinal0 argument must be "
"%select{a vector, integer or floating point type|a matrix|"
Expand Down Expand Up @@ -12364,6 +12368,7 @@ def err_hlsl_packoffset_cross_reg_boundary : Error<"packoffset cannot cross regi
def err_hlsl_packoffset_alignment_mismatch : Error<"packoffset at 'y' not match alignment %0 required by %1">;
def err_hlsl_pointers_unsupported : Error<
"%select{pointers|references}0 are unsupported in HLSL">;
def err_hlsl_missing_resource_class : Error<"HLSL resource needs to have [[hlsl::resource_class()]] attribute">;

def err_hlsl_operator_unsupported : Error<
"the '%select{&|*|->}0' operator is unsupported in HLSL">;
Expand Down Expand Up @@ -12412,6 +12417,13 @@ def warn_unsafe_buffer_operation : Warning<
"unsafe buffer access|function introduces unsafe buffer manipulation|unsafe invocation of span::data|"
"field %1 prone to unsafe buffer manipulation}0">,
InGroup<UnsafeBufferUsage>, DefaultIgnore;
def warn_unsafe_buffer_libc_call : Warning<
"function %0 is unsafe">,
InGroup<UnsafeBufferUsageInLibcCall>, DefaultIgnore;
def note_unsafe_buffer_printf_call : Note<
"%select{|change to 'snprintf' for explicit bounds checking | buffer pointer and size may not match"
"|string argument is not guaranteed to be null-terminated"
"|'va_list' is unsafe}0">;
def note_unsafe_buffer_operation : Note<
"used%select{| in pointer arithmetic| in buffer access}0 here">;
def note_unsafe_buffer_variable_fixit_group : Note<
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/SourceManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -724,7 +724,7 @@ class SourceManager : public RefCountedBase<SourceManager> {
///
/// Negative FileIDs are indexes into this table. To get from ID to an index,
/// use (-ID - 2).
llvm::PagedVector<SrcMgr::SLocEntry> LoadedSLocEntryTable;
llvm::PagedVector<SrcMgr::SLocEntry, 32> LoadedSLocEntryTable;

/// For each allocation in LoadedSLocEntryTable, we keep the first FileID.
/// We assume exactly one allocation per AST file, and use that to determine
Expand Down
12 changes: 5 additions & 7 deletions clang/include/clang/Basic/TargetCXXABI.def
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
/// many compilers, including Clang and GCC.
///
/// It is documented here:
/// http://www.codesourcery.com/public/cxx-abi/
/// http://itanium-cxx-abi.github.io/cxx-abi/
ITANIUM_CXXABI(GenericItanium, "itanium")

/// The generic ARM ABI is a modified version of the Itanium ABI
Expand All @@ -46,8 +46,7 @@ ITANIUM_CXXABI(GenericItanium, "itanium")
/// - and more!
///
/// It is documented here:
/// http://infocenter.arm.com
/// /help/topic/com.arm.doc.ihi0041c/IHI0041C_cppabi.pdf
/// https://github.com/ARM-software/abi-aa/blob/main/cppabi32/cppabi32.rst
ITANIUM_CXXABI(GenericARM, "arm")

/// The iOS ABI is a partial implementation of the ARM ABI.
Expand All @@ -63,10 +62,6 @@ ITANIUM_CXXABI(iOS, "ios")

/// The iOS 64-bit and macOS 64-bit ARM ABI follows ARM's published 64-bit
/// ABI more closely, but we don't guarantee to follow it perfectly.
///
/// It is documented here:
/// http://infocenter.arm.com
/// /help/topic/com.arm.doc.ihi0059a/IHI0059A_cppabi64.pdf
ITANIUM_CXXABI(AppleARM64, "applearm64")

/// WatchOS is a modernisation of the iOS ABI, which roughly means it's
Expand All @@ -80,6 +75,9 @@ ITANIUM_CXXABI(WatchOS, "watchos")
/// The relevant changes from the generic ABI in this case are:
/// - representation of member function pointers adjusted as in ARM.
/// - guard variables are smaller.
///
/// It is documented here:
/// https://github.com/ARM-software/abi-aa/blob/main/cppabi64/cppabi64.rst
ITANIUM_CXXABI(GenericAArch64, "aarch64")

/// The generic Mips ABI is a modified version of the Itanium ABI.
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Basic/TokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -660,8 +660,9 @@ KEYWORD(out , KEYHLSL)
#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) KEYWORD(Name, KEYHLSL)
#include "clang/Basic/HLSLIntangibleTypes.def"

// HLSL Type traits.
// HLSL Type traits
TYPE_TRAIT_2(__builtin_hlsl_is_scalarized_layout_compatible, IsScalarizedLayoutCompatible, KEYHLSL)
TYPE_TRAIT_1(__builtin_hlsl_is_intangible, IsIntangibleType, KEYHLSL)

// OpenMP Type Traits
UNARY_EXPR_OR_TYPE_TRAIT(__builtin_omp_required_simd_align, OpenMPRequiredSimdAlign, KEYALL)
Expand Down
19 changes: 19 additions & 0 deletions clang/include/clang/Basic/arm_neon.td
Original file line number Diff line number Diff line change
Expand Up @@ -2096,3 +2096,22 @@ let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "r
def VLDAP1_LANE : WInst<"vldap1_lane", ".(c*!).I", "QUlQlUlldQdPlQPl">;
def VSTL1_LANE : WInst<"vstl1_lane", "v*(.!)I", "QUlQlUlldQdPlQPl">;
}

// Lookup table read with 2-bit/4-bit indices
let ArchGuard = "defined(__aarch64__)", TargetGuard = "lut" in {
def VLUTI2_B : SInst<"vluti2_lane", "Q.(qU)I", "cUcPcQcQUcQPc">;
def VLUTI2_B_Q : SInst<"vluti2_laneq", "Q.(QU)I", "cUcPcQcQUcQPc">;
def VLUTI2_H : SInst<"vluti2_lane", "Q.(<qU)I", "sUsPshQsQUsQPsQh">;
def VLUTI2_H_Q : SInst<"vluti2_laneq", "Q.(<QU)I", "sUsPshQsQUsQPsQh">;
def VLUTI4_B : SInst<"vluti4_lane", "..(qU)I", "QcQUcQPc">;
def VLUTI4_B_Q : SInst<"vluti4_laneq", "..UI", "QcQUcQPc">;
def VLUTI4_H_X2 : SInst<"vluti4_lane_x2", ".2(<qU)I", "QsQUsQPsQh">;
def VLUTI4_H_X2_Q : SInst<"vluti4_laneq_x2", ".2(<U)I", "QsQUsQPsQh">;

let ArchGuard = "defined(__aarch64__)", TargetGuard= "lut,bf16" in {
def VLUTI2_BF : SInst<"vluti2_lane", "Q.(<qU)I", "bQb">;
def VLUTI2_BF_Q : SInst<"vluti2_laneq", "Q.(<QU)I", "bQb">;
def VLUTI4_BF_X2 : SInst<"vluti4_lane_x2", ".2(<qU)I", "Qb">;
def VLUTI4_BF_X2_Q : SInst<"vluti4_laneq_x2", ".2(<U)I", "Qb">;
}
}
30 changes: 30 additions & 0 deletions clang/include/clang/Basic/arm_sve.td
Original file line number Diff line number Diff line change
Expand Up @@ -1939,6 +1939,24 @@ def SVTBL2_BF16 : SInst<"svtbl2[_{d}]", "d2u", "b", MergeNone, "", [VerifyRunti
def SVTBX_BF16 : SInst<"svtbx[_{d}]", "dddu", "b", MergeNone, "aarch64_sve_tbx", [VerifyRuntimeMode]>;
}

////////////////////////////////////////////////////////////////////////////////
// SVE2 - Lookup table
let SVETargetGuard = "sve2,lut", SMETargetGuard = "sme2,lut" in {
def SVLUTI2_B : SInst<"svluti2_lane[_{d}]", "dd[i", "cUc", MergeNone, "aarch64_sve_luti2_lane", [VerifyRuntimeMode], [ImmCheck<2, ImmCheck0_3>]>;
def SVLUTI2_H : SInst<"svluti2_lane[_{d}]", "dd[i", "sUsh", MergeNone, "aarch64_sve_luti2_lane", [VerifyRuntimeMode], [ImmCheck<2, ImmCheck0_7>]>;

def SVLUTI4_B : SInst<"svluti4_lane[_{d}]", "dd[i", "cUc", MergeNone, "aarch64_sve_luti4_lane", [VerifyRuntimeMode], [ImmCheck<2, ImmCheck0_1>]>;
def SVLUTI4_H : SInst<"svluti4_lane[_{d}]", "dd[i", "sUsh", MergeNone, "aarch64_sve_luti4_lane", [VerifyRuntimeMode], [ImmCheck<2, ImmCheck0_3>]>;

def SVLUTI4_x2 : SInst<"svluti4_lane[_{d}]_x2", "d2.d[i", "sUsh", MergeNone, "aarch64_sve_luti4_lane_x2", [VerifyRuntimeMode], [ImmCheck<2, ImmCheck0_3>]>;
}

let SVETargetGuard = "sve2,lut,bf16", SMETargetGuard = "sme2,lut,bf16" in {
def SVLUTI2_BF16 : SInst<"svluti2_lane[_{d}]", "dd[i", "b", MergeNone, "aarch64_sve_luti2_lane", [ VerifyRuntimeMode], [ImmCheck<2, ImmCheck0_7>]>;
def SVLUTI4_BF16 : SInst<"svluti4_lane[_{d}]", "dd[i", "b", MergeNone, "aarch64_sve_luti4_lane", [ VerifyRuntimeMode], [ImmCheck<2, ImmCheck0_3>]>;
def SVLUTI4_BF16_x2 : SInst<"svluti4_lane[_{d}]_x2", "d2.d[i", "b", MergeNone, "aarch64_sve_luti4_lane_x2", [ VerifyRuntimeMode], [ImmCheck<2, ImmCheck0_3>]>;
}

////////////////////////////////////////////////////////////////////////////////
// SVE2 - Optional

Expand Down Expand Up @@ -2235,6 +2253,13 @@ let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in {
def SVSQDMULH_X4 : SInst<"svqdmulh[_{d}_x4]", "444", "csil", MergeNone, "aarch64_sve_sqdmulh_vgx4", [IsStreaming], []>;
}

let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2,faminmax" in {
def FAMIN_X2 : Inst<"svamin[_{d}_x2]", "222", "hfd", MergeNone, "aarch64_sme_famin_x2", [IsStreaming], []>;
def FAMAX_X2 : Inst<"svamax[_{d}_x2]", "222", "hfd", MergeNone, "aarch64_sme_famax_x2", [IsStreaming], []>;
def FAMIN_X4 : Inst<"svamin[_{d}_x4]", "444", "hfd", MergeNone, "aarch64_sme_famin_x4", [IsStreaming], []>;
def FAMAX_X4 : Inst<"svamax[_{d}_x4]", "444", "hfd", MergeNone, "aarch64_sme_famax_x4", [IsStreaming], []>;
}

let SVETargetGuard = "sve2p1", SMETargetGuard = "sme2" in {
def REINTERPRET_SVBOOL_TO_SVCOUNT : Inst<"svreinterpret[_c]", "}P", "Pc", MergeNone, "", [VerifyRuntimeMode], []>;
def REINTERPRET_SVCOUNT_TO_SVBOOL : Inst<"svreinterpret[_b]", "P}", "Pc", MergeNone, "", [VerifyRuntimeMode], []>;
Expand Down Expand Up @@ -2401,3 +2426,8 @@ let SVETargetGuard = "sve2p1", SMETargetGuard = "sme2" in {
def SVBFMLSLB_LANE : SInst<"svbfmlslb_lane[_{d}]", "dd$$i", "f", MergeNone, "aarch64_sve_bfmlslb_lane", [IsOverloadNone, VerifyRuntimeMode], [ImmCheck<3, ImmCheck0_7>]>;
def SVBFMLSLT_LANE : SInst<"svbfmlslt_lane[_{d}]", "dd$$i", "f", MergeNone, "aarch64_sve_bfmlslt_lane", [IsOverloadNone, VerifyRuntimeMode], [ImmCheck<3, ImmCheck0_7>]>;
}

let SVETargetGuard = "sve2,faminmax", SMETargetGuard = "sme2,faminmax" in {
defm SVAMIN : SInstZPZZ<"svamin", "hfd", "aarch64_sve_famin", "aarch64_sve_famin_u">;
defm SVAMAX : SInstZPZZ<"svamax", "hfd", "aarch64_sve_famax", "aarch64_sve_famax_u">;
}
2 changes: 1 addition & 1 deletion clang/include/clang/CodeGen/CodeGenAction.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class CodeGenAction : public ASTFrontendAction {
bool loadLinkModules(CompilerInstance &CI);

protected:
bool BeginInvocation(CompilerInstance &CI) override;
bool BeginSourceFileAction(CompilerInstance &CI) override;

/// Create a new code generation action. If the optional \p _VMContext
/// parameter is supplied, the action uses it without taking ownership,
Expand Down
17 changes: 15 additions & 2 deletions clang/include/clang/Driver/Multilib.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@
#include "llvm/Support/SourceMgr.h"
#include <cassert>
#include <functional>
#include <optional>
#include <string>
#include <utility>
#include <vector>

namespace clang {
namespace driver {

class Driver;

/// This corresponds to a single GCC Multilib, or a segment of one controlled
/// by a command line flag.
/// See also MultilibBuilder for building a multilib by mutating it
Expand All @@ -48,13 +51,19 @@ class Multilib {
// directory is not mutually exclusive with anything else.
std::string ExclusiveGroup;

// Some Multilib objects don't actually represent library directories you can
// select. Instead, they represent failures of multilib selection, of the
// form 'Sorry, we don't have any library compatible with these constraints'.
std::optional<std::string> FatalError;

public:
/// GCCSuffix, OSSuffix & IncludeSuffix will be appended directly to the
/// sysroot string so they must either be empty or begin with a '/' character.
/// This is enforced with an assert in the constructor.
Multilib(StringRef GCCSuffix = {}, StringRef OSSuffix = {},
StringRef IncludeSuffix = {}, const flags_list &Flags = flags_list(),
StringRef ExclusiveGroup = {});
StringRef ExclusiveGroup = {},
std::optional<StringRef> FatalError = std::nullopt);

/// Get the detected GCC installation path suffix for the multi-arch
/// target variant. Always starts with a '/', unless empty
Expand Down Expand Up @@ -84,6 +93,10 @@ class Multilib {
{ return GCCSuffix.empty() && OSSuffix.empty() && IncludeSuffix.empty(); }

bool operator==(const Multilib &Other) const;

bool isFatalError() const { return FatalError.has_value(); }

const std::string &getFatalError() const { return FatalError.value(); }
};

raw_ostream &operator<<(raw_ostream &OS, const Multilib &M);
Expand Down Expand Up @@ -129,7 +142,7 @@ class MultilibSet {
const_iterator end() const { return Multilibs.end(); }

/// Select compatible variants, \returns false if none are compatible
bool select(const Multilib::flags_list &Flags,
bool select(const Driver &D, const Multilib::flags_list &Flags,
llvm::SmallVectorImpl<Multilib> &) const;

unsigned size() const { return Multilibs.size(); }
Expand Down
9 changes: 9 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -3545,6 +3545,7 @@ def fopenmp : Flag<["-"], "fopenmp">, Group<f_Group>,
Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>,
HelpText<"Parse OpenMP pragmas and generate parallel code.">;
def fno_openmp : Flag<["-"], "fno-openmp">, Group<f_Group>,
Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>,
Flags<[NoArgumentUnused]>;
class OpenMPVersionHelp<string program, string default> {
string str = !strconcat(
Expand Down Expand Up @@ -6761,6 +6762,14 @@ def fdefault_integer_8 : Flag<["-"],"fdefault-integer-8">, Group<f_Group>,
HelpText<"Set the default integer and logical kind to an 8 byte wide type">;
def fdefault_real_8 : Flag<["-"],"fdefault-real-8">, Group<f_Group>,
HelpText<"Set the default real kind to an 8 byte wide type">;
def fdisable_real_3 : Flag<["-"],"fdisable-real-3">, Group<f_Group>,
HelpText<"Disable real(KIND=3) from TargetCharacteristics">, Flags<[HelpHidden]>;
def fdisable_real_10 : Flag<["-"],"fdisable-real-10">, Group<f_Group>,
HelpText<"Disable real(KIND=10) from TargetCharacteristics">, Flags<[HelpHidden]>;
def fdisable_integer_2 : Flag<["-"],"fdisable-integer-2">, Group<f_Group>,
HelpText<"Disable integer(KIND=2) from TargetCharacteristics">, Flags<[HelpHidden]>;
def fdisable_integer_16 : Flag<["-"],"fdisable-integer-16">, Group<f_Group>,
HelpText<"Disable integer(KIND=16) from TargetCharacteristics">, Flags<[HelpHidden]>;
def flarge_sizes : Flag<["-"],"flarge-sizes">, Group<f_Group>,
HelpText<"Use INTEGER(KIND=8) for the result type in size-related intrinsics">;

Expand Down
4 changes: 1 addition & 3 deletions clang/include/clang/Frontend/FrontendActions.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,13 +152,11 @@ class GenerateModuleFromModuleMapAction : public GenerateModuleAction {
CreateOutputFile(CompilerInstance &CI, StringRef InFile) override;
};

bool BeginInvocationForModules(CompilerInstance &CI);

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

std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) override;
Expand Down
21 changes: 19 additions & 2 deletions clang/include/clang/Sema/SemaHLSL.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@

#include "clang/AST/ASTFwd.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Type.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Sema/SemaBase.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/TargetParser/Triple.h"
#include <initializer_list>

Expand All @@ -26,6 +28,12 @@ class IdentifierInfo;
class ParsedAttr;
class Scope;

// FIXME: This can be hidden (as static function in SemaHLSL.cpp) once we no
// longer need to create builtin buffer types in HLSLExternalSemaSource.
bool CreateHLSLAttributedResourceType(Sema &S, QualType Wrapped,
ArrayRef<const Attr *> AttrList,
QualType &ResType);

class SemaHLSL : public SemaBase {
public:
SemaHLSL(Sema &S);
Expand Down Expand Up @@ -59,8 +67,6 @@ class SemaHLSL : public SemaBase {
void handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL);
void handlePackOffsetAttr(Decl *D, const ParsedAttr &AL);
void handleShaderAttr(Decl *D, const ParsedAttr &AL);
void handleROVAttr(Decl *D, const ParsedAttr &AL);
void handleResourceClassAttr(Decl *D, const ParsedAttr &AL);
void handleResourceBindingAttr(Decl *D, const ParsedAttr &AL);
void handleParamModifierAttr(Decl *D, const ParsedAttr &AL);
bool handleResourceTypeAttr(const ParsedAttr &AL);
Expand All @@ -71,12 +77,23 @@ class SemaHLSL : public SemaBase {

// HLSL Type trait implementations
bool IsScalarizedLayoutCompatible(QualType T1, QualType T2) const;
bool IsIntangibleType(QualType T1);

bool CheckCompatibleParameterABI(FunctionDecl *New, FunctionDecl *Old);

ExprResult ActOnOutParamExpr(ParmVarDecl *Param, Expr *Arg);

QualType getInoutParameterType(QualType Ty);

private:
// HLSL resource type attributes need to be processed all at once.
// This is a list to collect them.
llvm::SmallVector<const Attr *> HLSLResourcesTypeAttrs;

/// SourceLocation corresponding to HLSLAttributedResourceTypeLocs that we
/// have not yet populated.
llvm::DenseMap<const HLSLAttributedResourceType *, SourceLocation>
LocsForHLSLAttributedResources;
};

} // namespace clang
Expand Down
10 changes: 5 additions & 5 deletions clang/include/clang/Serialization/ModuleFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,13 @@ class InputFile {

InputFile(FileEntryRef File, bool isOverridden = false,
bool isOutOfDate = false) {
assert(!(isOverridden && isOutOfDate) &&
"an overridden cannot be out-of-date");
unsigned intVal = 0;
// Make isOutOfDate with higher priority than isOverridden.
// It is possible if the recorded hash value mismatches.
if (isOutOfDate)
intVal = OutOfDate;
else if (isOverridden)
if (isOverridden)
intVal = Overridden;
else if (isOutOfDate)
intVal = OutOfDate;
Val.setPointerAndInt(&File.getMapEntry(), intVal);
}

Expand Down
8 changes: 4 additions & 4 deletions clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
Original file line number Diff line number Diff line change
Expand Up @@ -1000,6 +1000,10 @@ def FloatLoopCounter : Checker<"FloatLoopCounter">,
Dependencies<[SecuritySyntaxChecker]>,
Documentation<HasDocumentation>;

def MmapWriteExecChecker : Checker<"MmapWriteExec">,
HelpText<"Warn on mmap() calls with both writable and executable access">,
Documentation<HasDocumentation>;

def PutenvStackArray : Checker<"PutenvStackArray">,
HelpText<"Finds calls to the function 'putenv' which pass a pointer to "
"an automatic (stack-allocated) array as the argument.">,
Expand Down Expand Up @@ -1039,10 +1043,6 @@ def ArrayBoundCheckerV2 : Checker<"ArrayBoundV2">,
HelpText<"Warn about buffer overflows (newer checker)">,
Documentation<HasDocumentation>;

def MmapWriteExecChecker : Checker<"MmapWriteExec">,
HelpText<"Warn on mmap() calls that are both writable and executable">,
Documentation<HasDocumentation>;

def ReturnPointerRangeChecker : Checker<"ReturnPtrRange">,
HelpText<"Check for an out-of-bound pointer being returned to callers">,
Documentation<HasDocumentation>;
Expand Down
18 changes: 10 additions & 8 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6188,20 +6188,22 @@ QualType ASTContext::getPackIndexingType(QualType Pattern, Expr *IndexExpr,
ArrayRef<QualType> Expansions,
int Index) const {
QualType Canonical;
bool ExpandsToEmptyPack = FullySubstituted && Expansions.empty();
if (FullySubstituted && Index != -1) {
Canonical = getCanonicalType(Expansions[Index]);
} else {
llvm::FoldingSetNodeID ID;
PackIndexingType::Profile(ID, *this, Pattern, IndexExpr);
PackIndexingType::Profile(ID, *this, Pattern, IndexExpr,
ExpandsToEmptyPack);
void *InsertPos = nullptr;
PackIndexingType *Canon =
DependentPackIndexingTypes.FindNodeOrInsertPos(ID, InsertPos);
if (!Canon) {
void *Mem = Allocate(
PackIndexingType::totalSizeToAlloc<QualType>(Expansions.size()),
TypeAlignment);
Canon = new (Mem)
PackIndexingType(*this, QualType(), Pattern, IndexExpr, Expansions);
Canon = new (Mem) PackIndexingType(*this, QualType(), Pattern, IndexExpr,
ExpandsToEmptyPack, Expansions);
DependentPackIndexingTypes.InsertNode(Canon, InsertPos);
}
Canonical = QualType(Canon, 0);
Expand All @@ -6210,8 +6212,8 @@ QualType ASTContext::getPackIndexingType(QualType Pattern, Expr *IndexExpr,
void *Mem =
Allocate(PackIndexingType::totalSizeToAlloc<QualType>(Expansions.size()),
TypeAlignment);
auto *T = new (Mem)
PackIndexingType(*this, Canonical, Pattern, IndexExpr, Expansions);
auto *T = new (Mem) PackIndexingType(*this, Canonical, Pattern, IndexExpr,
ExpandsToEmptyPack, Expansions);
Types.push_back(T);
return QualType(T, 0);
}
Expand Down Expand Up @@ -6581,7 +6583,7 @@ QualType ASTContext::getUnqualifiedArrayType(QualType type,
/// \param AllowPiMismatch Allow the Pi1 and Pi2 to differ as described in
/// C++20 [conv.qual], if permitted by the current language mode.
void ASTContext::UnwrapSimilarArrayTypes(QualType &T1, QualType &T2,
bool AllowPiMismatch) {
bool AllowPiMismatch) const {
while (true) {
auto *AT1 = getAsArrayType(T1);
if (!AT1)
Expand Down Expand Up @@ -6632,7 +6634,7 @@ void ASTContext::UnwrapSimilarArrayTypes(QualType &T1, QualType &T2,
/// \return \c true if a pointer type was unwrapped, \c false if we reached a
/// pair of types that can't be unwrapped further.
bool ASTContext::UnwrapSimilarTypes(QualType &T1, QualType &T2,
bool AllowPiMismatch) {
bool AllowPiMismatch) const {
UnwrapSimilarArrayTypes(T1, T2, AllowPiMismatch);

const auto *T1PtrType = T1->getAs<PointerType>();
Expand Down Expand Up @@ -6668,7 +6670,7 @@ bool ASTContext::UnwrapSimilarTypes(QualType &T1, QualType &T2,
return false;
}

bool ASTContext::hasSimilarType(QualType T1, QualType T2) {
bool ASTContext::hasSimilarType(QualType T1, QualType T2) const {
while (true) {
Qualifiers Quals;
T1 = getUnqualifiedArrayType(T1, Quals);
Expand Down
118 changes: 43 additions & 75 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -360,51 +360,42 @@ namespace clang {
}

template <typename TemplateParmDeclT>
void tryUpdateTemplateParmDeclInheritedFrom(NamedDecl *RecentParm,
NamedDecl *NewParm) {
if (auto *ParmT = dyn_cast<TemplateParmDeclT>(RecentParm)) {
if (ParmT->hasDefaultArgument()) {
auto *P = cast<TemplateParmDeclT>(NewParm);
P->removeDefaultArgument();
P->setInheritedDefaultArgument(Importer.ToContext, ParmT);
Error importTemplateParameterDefaultArgument(const TemplateParmDeclT *D,
TemplateParmDeclT *ToD) {
Error Err = Error::success();
if (D->hasDefaultArgument()) {
if (D->defaultArgumentWasInherited()) {
auto *ToInheritedFrom = const_cast<TemplateParmDeclT *>(
importChecked(Err, D->getDefaultArgStorage().getInheritedFrom()));
if (Err)
return Err;
if (!ToInheritedFrom->hasDefaultArgument()) {
// Resolve possible circular dependency between default value of the
// template argument and the template declaration.
const auto ToInheritedDefaultArg =
importChecked(Err, D->getDefaultArgStorage()
.getInheritedFrom()
->getDefaultArgument());
if (Err)
return Err;
ToInheritedFrom->setDefaultArgument(Importer.getToContext(),
ToInheritedDefaultArg);
}
ToD->setInheritedDefaultArgument(ToD->getASTContext(),
ToInheritedFrom);
} else {
Expected<TemplateArgumentLoc> ToDefaultArgOrErr =
import(D->getDefaultArgument());
if (!ToDefaultArgOrErr)
return ToDefaultArgOrErr.takeError();
// Default argument could have been set in the
// '!ToInheritedFrom->hasDefaultArgument()' branch above.
if (!ToD->hasDefaultArgument())
ToD->setDefaultArgument(Importer.getToContext(),
*ToDefaultArgOrErr);
}
}
}

// Update the parameter list `NewParams` of a template declaration
// by "inheriting" default argument values from `RecentParams`,
// which is the parameter list of an earlier declaration of the
// same template. (Note that "inheriting" default argument values
// is not related to object-oriented inheritance.)
//
// In the clang AST template parameters (NonTypeTemplateParmDec,
// TemplateTypeParmDecl, TemplateTemplateParmDecl) have a reference to the
// default value, if one is specified at the first declaration. The default
// value can be specified only once. The template parameters of the
// following declarations have a reference to the original default value
// through the "inherited" value. This value should be set for all imported
// template parameters that have a previous declaration (also a previous
// template declaration).
//
// In the `Visit*ParmDecl` functions the default value of these template
// arguments is always imported. At that location the previous declaration
// is not easily accessible, it is not possible to call
// `setInheritedDefaultArgument` at that place.
// `updateTemplateParametersInheritedFrom` is called later when the already
// imported default value is erased and changed to "inherited".
// It is important to change the mode to "inherited" otherwise false
// structural in-equivalences could be detected.
void updateTemplateParametersInheritedFrom(
const TemplateParameterList &RecentParams,
TemplateParameterList &NewParams) {
for (auto [Idx, Param] : enumerate(RecentParams)) {
tryUpdateTemplateParmDeclInheritedFrom<NonTypeTemplateParmDecl>(
Param, NewParams.getParam(Idx));
tryUpdateTemplateParmDeclInheritedFrom<TemplateTypeParmDecl>(
Param, NewParams.getParam(Idx));
tryUpdateTemplateParmDeclInheritedFrom<TemplateTemplateParmDecl>(
Param, NewParams.getParam(Idx));
}
return Err;
}

public:
Expand Down Expand Up @@ -5955,8 +5946,8 @@ ASTNodeImporter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
ExpectedDecl
ASTNodeImporter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
// For template arguments, we adopt the translation unit as our declaration
// context. This context will be fixed when the actual template declaration
// is created.
// context. This context will be fixed when (during) the actual template
// declaration is created.

ExpectedSLoc BeginLocOrErr = import(D->getBeginLoc());
if (!BeginLocOrErr)
Expand Down Expand Up @@ -5988,13 +5979,8 @@ ASTNodeImporter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
ToD->setTypeConstraint(ToConceptRef, ToIDC);
}

if (D->hasDefaultArgument()) {
Expected<TemplateArgumentLoc> ToDefaultArgOrErr =
import(D->getDefaultArgument());
if (!ToDefaultArgOrErr)
return ToDefaultArgOrErr.takeError();
ToD->setDefaultArgument(ToD->getASTContext(), *ToDefaultArgOrErr);
}
if (Error Err = importTemplateParameterDefaultArgument(D, ToD))
return Err;

return ToD;
}
Expand All @@ -6020,13 +6006,9 @@ ASTNodeImporter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
D->isParameterPack(), ToTypeSourceInfo))
return ToD;

if (D->hasDefaultArgument()) {
Expected<TemplateArgumentLoc> ToDefaultArgOrErr =
import(D->getDefaultArgument());
if (!ToDefaultArgOrErr)
return ToDefaultArgOrErr.takeError();
ToD->setDefaultArgument(Importer.getToContext(), *ToDefaultArgOrErr);
}
Err = importTemplateParameterDefaultArgument(D, ToD);
if (Err)
return Err;

return ToD;
}
Expand Down Expand Up @@ -6057,13 +6039,8 @@ ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
*TemplateParamsOrErr))
return ToD;

if (D->hasDefaultArgument()) {
Expected<TemplateArgumentLoc> ToDefaultArgOrErr =
import(D->getDefaultArgument());
if (!ToDefaultArgOrErr)
return ToDefaultArgOrErr.takeError();
ToD->setDefaultArgument(Importer.getToContext(), *ToDefaultArgOrErr);
}
if (Error Err = importTemplateParameterDefaultArgument(D, ToD))
return Err;

return ToD;
}
Expand Down Expand Up @@ -6201,9 +6178,6 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
}

D2->setPreviousDecl(Recent);

updateTemplateParametersInheritedFrom(*(Recent->getTemplateParameters()),
**TemplateParamsOrErr);
}

return D2;
Expand Down Expand Up @@ -6518,9 +6492,6 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) {
ToTemplated->setPreviousDecl(PrevTemplated);
}
ToVarTD->setPreviousDecl(Recent);

updateTemplateParametersInheritedFrom(*(Recent->getTemplateParameters()),
**TemplateParamsOrErr);
}

return ToVarTD;
Expand Down Expand Up @@ -6793,9 +6764,6 @@ ASTNodeImporter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
TemplatedFD->setPreviousDecl(PrevTemplated);
}
ToFunc->setPreviousDecl(Recent);

updateTemplateParametersInheritedFrom(*(Recent->getTemplateParameters()),
*Params);
}

return ToFunc;
Expand Down
76 changes: 36 additions & 40 deletions clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,8 +298,8 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
return false;

const auto *TargetSemantics = &Ctx.getFloatSemantics(CE->getType());
llvm::RoundingMode RM = getRoundingMode(CE);
return this->emitCastIntegralFloating(*FromT, TargetSemantics, RM, CE);
return this->emitCastIntegralFloating(*FromT, TargetSemantics,
getFPOptions(CE), CE);
}

case CK_FloatingToBoolean:
Expand All @@ -317,12 +317,12 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {

if (ToT == PT_IntAP)
return this->emitCastFloatingIntegralAP(Ctx.getBitWidth(CE->getType()),
CE);
getFPOptions(CE), CE);
if (ToT == PT_IntAPS)
return this->emitCastFloatingIntegralAPS(Ctx.getBitWidth(CE->getType()),
CE);
getFPOptions(CE), CE);

return this->emitCastFloatingIntegral(*ToT, CE);
return this->emitCastFloatingIntegral(*ToT, getFPOptions(CE), CE);
}

case CK_NullToPointer:
Expand Down Expand Up @@ -810,21 +810,21 @@ bool Compiler<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {
return MaybeCastToBool(this->emitGE(*LT, BO));
case BO_Sub:
if (BO->getType()->isFloatingType())
return Discard(this->emitSubf(getRoundingMode(BO), BO));
return Discard(this->emitSubf(getFPOptions(BO), BO));
return Discard(this->emitSub(*T, BO));
case BO_Add:
if (BO->getType()->isFloatingType())
return Discard(this->emitAddf(getRoundingMode(BO), BO));
return Discard(this->emitAddf(getFPOptions(BO), BO));
return Discard(this->emitAdd(*T, BO));
case BO_Mul:
if (BO->getType()->isFloatingType())
return Discard(this->emitMulf(getRoundingMode(BO), BO));
return Discard(this->emitMulf(getFPOptions(BO), BO));
return Discard(this->emitMul(*T, BO));
case BO_Rem:
return Discard(this->emitRem(*T, BO));
case BO_Div:
if (BO->getType()->isFloatingType())
return Discard(this->emitDivf(getRoundingMode(BO), BO));
return Discard(this->emitDivf(getFPOptions(BO), BO));
return Discard(this->emitDiv(*T, BO));
case BO_Assign:
if (DiscardResult)
Expand Down Expand Up @@ -1153,7 +1153,7 @@ bool Compiler<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
if (!loadComplexValue(RHSIsComplex, true, ElemIndex, RHSOffset, RHS))
return false;
if (ResultElemT == PT_Float) {
if (!this->emitAddf(getRoundingMode(E), E))
if (!this->emitAddf(getFPOptions(E), E))
return false;
} else {
if (!this->emitAdd(ResultElemT, E))
Expand All @@ -1167,7 +1167,7 @@ bool Compiler<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
if (!loadComplexValue(RHSIsComplex, true, ElemIndex, RHSOffset, RHS))
return false;
if (ResultElemT == PT_Float) {
if (!this->emitSubf(getRoundingMode(E), E))
if (!this->emitSubf(getFPOptions(E), E))
return false;
} else {
if (!this->emitSub(ResultElemT, E))
Expand All @@ -1182,7 +1182,7 @@ bool Compiler<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
return false;

if (ResultElemT == PT_Float) {
if (!this->emitMulf(getRoundingMode(E), E))
if (!this->emitMulf(getFPOptions(E), E))
return false;
} else {
if (!this->emitMul(ResultElemT, E))
Expand All @@ -1198,7 +1198,7 @@ bool Compiler<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
return false;

if (ResultElemT == PT_Float) {
if (!this->emitDivf(getRoundingMode(E), E))
if (!this->emitDivf(getFPOptions(E), E))
return false;
} else {
if (!this->emitDiv(ResultElemT, E))
Expand Down Expand Up @@ -1235,12 +1235,6 @@ bool Compiler<Emitter>::VisitImplicitValueInitExpr(
assert(RD);
if (RD->isInvalidDecl())
return false;
if (RD->isUnion()) {
// C++11 [dcl.init]p5: If T is a (possibly cv-qualified) union type, the
// object's first non-static named data member is zero-initialized
// FIXME
return false;
}

if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD);
CXXRD && CXXRD->getNumVBases() > 0) {
Expand Down Expand Up @@ -2069,22 +2063,21 @@ bool Compiler<Emitter>::VisitFloatCompoundAssignOperator(
if (!this->emitGetLocal(*RT, TempOffset, E))
return false;

llvm::RoundingMode RM = getRoundingMode(E);
switch (E->getOpcode()) {
case BO_AddAssign:
if (!this->emitAddf(RM, E))
if (!this->emitAddf(getFPOptions(E), E))
return false;
break;
case BO_SubAssign:
if (!this->emitSubf(RM, E))
if (!this->emitSubf(getFPOptions(E), E))
return false;
break;
case BO_MulAssign:
if (!this->emitMulf(RM, E))
if (!this->emitMulf(getFPOptions(E), E))
return false;
break;
case BO_DivAssign:
if (!this->emitDivf(RM, E))
if (!this->emitDivf(getFPOptions(E), E))
return false;
break;
default:
Expand Down Expand Up @@ -3331,7 +3324,7 @@ template <class Emitter> bool Compiler<Emitter>::visitBool(const Expr *E) {

// Or Floats.
if (T == PT_Float)
return this->emitCastFloatingIntegralBool(E);
return this->emitCastFloatingIntegralBool(getFPOptions(E), E);

// Or anything else we can.
return this->emitCast(*T, PT_Bool, E);
Expand Down Expand Up @@ -3434,6 +3427,8 @@ bool Compiler<Emitter>::visitZeroRecordInitializer(const Record *R,
if (!this->emitFinishInitPop(E))
return false;

// C++11 [dcl.init]p5: If T is a (possibly cv-qualified) union type, the
// object's first non-static named data member is zero-initialized
if (R->isUnion())
break;
}
Expand Down Expand Up @@ -5009,8 +5004,8 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
}

if (T == PT_Float) {
return DiscardResult ? this->emitIncfPop(getRoundingMode(E), E)
: this->emitIncf(getRoundingMode(E), E);
return DiscardResult ? this->emitIncfPop(getFPOptions(E), E)
: this->emitIncf(getFPOptions(E), E);
}

return DiscardResult ? this->emitIncPop(*T, E) : this->emitInc(*T, E);
Expand All @@ -5032,8 +5027,8 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
}

if (T == PT_Float) {
return DiscardResult ? this->emitDecfPop(getRoundingMode(E), E)
: this->emitDecf(getRoundingMode(E), E);
return DiscardResult ? this->emitDecfPop(getFPOptions(E), E)
: this->emitDecf(getFPOptions(E), E);
}

return DiscardResult ? this->emitDecPop(*T, E) : this->emitDec(*T, E);
Expand All @@ -5060,7 +5055,7 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
// Post-inc and pre-inc are the same if the value is to be discarded.
if (DiscardResult) {
if (T == PT_Float)
return this->emitIncfPop(getRoundingMode(E), E);
return this->emitIncfPop(getFPOptions(E), E);
return this->emitIncPop(*T, E);
}

Expand All @@ -5070,7 +5065,7 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
return false;
if (!this->emitConstFloat(llvm::APFloat(TargetSemantics, 1), E))
return false;
if (!this->emitAddf(getRoundingMode(E), E))
if (!this->emitAddf(getFPOptions(E), E))
return false;
if (!this->emitStoreFloat(E))
return false;
Expand Down Expand Up @@ -5109,7 +5104,7 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
// Post-dec and pre-dec are the same if the value is to be discarded.
if (DiscardResult) {
if (T == PT_Float)
return this->emitDecfPop(getRoundingMode(E), E);
return this->emitDecfPop(getFPOptions(E), E);
return this->emitDecPop(*T, E);
}

Expand All @@ -5119,7 +5114,7 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
return false;
if (!this->emitConstFloat(llvm::APFloat(TargetSemantics, 1), E))
return false;
if (!this->emitSubf(getRoundingMode(E), E))
if (!this->emitSubf(getFPOptions(E), E))
return false;
if (!this->emitStoreFloat(E))
return false;
Expand Down Expand Up @@ -5583,13 +5578,15 @@ bool Compiler<Emitter>::emitPrimCast(PrimType FromT, PrimType ToT,
}

if (ToT == PT_IntAP)
return this->emitCastFloatingIntegralAP(Ctx.getBitWidth(ToQT), E);
return this->emitCastFloatingIntegralAP(Ctx.getBitWidth(ToQT),
getFPOptions(E), E);
if (ToT == PT_IntAPS)
return this->emitCastFloatingIntegralAPS(Ctx.getBitWidth(ToQT), E);
return this->emitCastFloatingIntegralAPS(Ctx.getBitWidth(ToQT),
getFPOptions(E), E);

// Float to integral.
if (isIntegralType(ToT) || ToT == PT_Bool)
return this->emitCastFloatingIntegral(ToT, E);
return this->emitCastFloatingIntegral(ToT, getFPOptions(E), E);
}

if (isIntegralType(FromT) || FromT == PT_Bool) {
Expand All @@ -5605,8 +5602,7 @@ bool Compiler<Emitter>::emitPrimCast(PrimType FromT, PrimType ToT,
if (ToT == PT_Float) {
// Integral to floating.
const llvm::fltSemantics *ToSem = &Ctx.getFloatSemantics(ToQT);
return this->emitCastIntegralFloating(FromT, ToSem, getRoundingMode(E),
E);
return this->emitCastIntegralFloating(FromT, ToSem, getFPOptions(E), E);
}
}

Expand Down Expand Up @@ -5643,7 +5639,7 @@ bool Compiler<Emitter>::emitComplexBoolCast(const Expr *E) {
if (!this->emitArrayElem(ElemT, 0, E))
return false;
if (ElemT == PT_Float) {
if (!this->emitCastFloatingIntegral(PT_Bool, E))
if (!this->emitCastFloatingIntegral(PT_Bool, getFPOptions(E), E))
return false;
} else {
if (!this->emitCast(ElemT, PT_Bool, E))
Expand All @@ -5658,7 +5654,7 @@ bool Compiler<Emitter>::emitComplexBoolCast(const Expr *E) {
if (!this->emitArrayElemPop(ElemT, 1, E))
return false;
if (ElemT == PT_Float) {
if (!this->emitCastFloatingIntegral(PT_Bool, E))
if (!this->emitCastFloatingIntegral(PT_Bool, getFPOptions(E), E))
return false;
} else {
if (!this->emitCast(ElemT, PT_Bool, E))
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/AST/ByteCode/Compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,10 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
return FPO.getRoundingMode();
}

uint32_t getFPOptions(const Expr *E) const {
return E->getFPFeaturesInEffect(Ctx.getLangOpts()).getAsOpaqueInt();
}

bool emitPrimCast(PrimType FromT, PrimType ToT, QualType ToQT, const Expr *E);
PrimType classifyComplexElementType(QualType T) const {
assert(T->isAnyComplexType());
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/AST/ByteCode/Function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ bool Function::isVirtual() const {
static bool isUnevaluatedBuiltin(unsigned BuiltinID) {
return BuiltinID == Builtin::BI__builtin_classify_type ||
BuiltinID == Builtin::BI__builtin_os_log_format_buffer_size ||
BuiltinID == Builtin::BI__builtin_constant_p;
BuiltinID == Builtin::BI__builtin_constant_p ||
BuiltinID == Builtin::BI__noop;
}

bool Function::isUnevaluatedBuiltin() const {
Expand Down
245 changes: 240 additions & 5 deletions clang/lib/AST/ByteCode/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -756,14 +756,13 @@ bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD) {
}

bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
APFloat::opStatus Status) {
const SourceInfo &E = S.Current->getSource(OpPC);

APFloat::opStatus Status, FPOptions FPO) {
// [expr.pre]p4:
// If during the evaluation of an expression, the result is not
// mathematically defined [...], the behavior is undefined.
// FIXME: C++ rules require us to not conform to IEEE 754 here.
if (Result.isNan()) {
const SourceInfo &E = S.Current->getSource(OpPC);
S.CCEDiag(E, diag::note_constexpr_float_arithmetic)
<< /*NaN=*/true << S.Current->getRange(OpPC);
return S.noteUndefinedBehavior();
Expand All @@ -774,12 +773,11 @@ bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
if (S.inConstantContext())
return true;

FPOptions FPO = E.asExpr()->getFPFeaturesInEffect(S.Ctx.getLangOpts());

if ((Status & APFloat::opInexact) &&
FPO.getRoundingMode() == llvm::RoundingMode::Dynamic) {
// Inexact result means that it depends on rounding mode. If the requested
// mode is dynamic, the evaluation cannot be made in compile time.
const SourceInfo &E = S.Current->getSource(OpPC);
S.FFDiag(E, diag::note_constexpr_dynamic_rounding);
return false;
}
Expand All @@ -788,12 +786,14 @@ bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
(FPO.getRoundingMode() == llvm::RoundingMode::Dynamic ||
FPO.getExceptionMode() != LangOptions::FPE_Ignore ||
FPO.getAllowFEnvAccess())) {
const SourceInfo &E = S.Current->getSource(OpPC);
S.FFDiag(E, diag::note_constexpr_float_arithmetic_strict);
return false;
}

if ((Status & APFloat::opStatus::opInvalidOp) &&
FPO.getExceptionMode() != LangOptions::FPE_Ignore) {
const SourceInfo &E = S.Current->getSource(OpPC);
// There is no usefully definable result.
S.FFDiag(E);
return false;
Expand Down Expand Up @@ -986,6 +986,241 @@ void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED,
}
}

bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,
uint32_t VarArgSize) {
if (Func->hasThisPointer()) {
size_t ArgSize = Func->getArgSize() + VarArgSize;
size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);

// If the current function is a lambda static invoker and
// the function we're about to call is a lambda call operator,
// skip the CheckInvoke, since the ThisPtr is a null pointer
// anyway.
if (!(S.Current->getFunction() &&
S.Current->getFunction()->isLambdaStaticInvoker() &&
Func->isLambdaCallOperator())) {
if (!CheckInvoke(S, OpPC, ThisPtr))
return false;
}

if (S.checkingPotentialConstantExpression())
return false;
}

if (!CheckCallable(S, OpPC, Func))
return false;

if (!CheckCallDepth(S, OpPC))
return false;

auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);
InterpFrame *FrameBefore = S.Current;
S.Current = NewFrame.get();

APValue CallResult;
// Note that we cannot assert(CallResult.hasValue()) here since
// Ret() above only sets the APValue if the curent frame doesn't
// have a caller set.
if (Interpret(S, CallResult)) {
NewFrame.release(); // Frame was delete'd already.
assert(S.Current == FrameBefore);
return true;
}

// Interpreting the function failed somehow. Reset to
// previous state.
S.Current = FrameBefore;
return false;
}

bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
uint32_t VarArgSize) {
if (Func->hasThisPointer()) {
size_t ArgSize = Func->getArgSize() + VarArgSize;
size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);

const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);

// If the current function is a lambda static invoker and
// the function we're about to call is a lambda call operator,
// skip the CheckInvoke, since the ThisPtr is a null pointer
// anyway.
if (S.Current->getFunction() &&
S.Current->getFunction()->isLambdaStaticInvoker() &&
Func->isLambdaCallOperator()) {
assert(ThisPtr.isZero());
} else {
if (!CheckInvoke(S, OpPC, ThisPtr))
return false;
}
}

if (!CheckCallable(S, OpPC, Func))
return false;

// FIXME: The isConstructor() check here is not always right. The current
// constant evaluator is somewhat inconsistent in when it allows a function
// call when checking for a constant expression.
if (Func->hasThisPointer() && S.checkingPotentialConstantExpression() &&
!Func->isConstructor())
return false;

if (!CheckCallDepth(S, OpPC))
return false;

auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);
InterpFrame *FrameBefore = S.Current;
S.Current = NewFrame.get();

APValue CallResult;
// Note that we cannot assert(CallResult.hasValue()) here since
// Ret() above only sets the APValue if the curent frame doesn't
// have a caller set.
if (Interpret(S, CallResult)) {
NewFrame.release(); // Frame was delete'd already.
assert(S.Current == FrameBefore);
return true;
}

// Interpreting the function failed somehow. Reset to
// previous state.
S.Current = FrameBefore;
return false;
}

bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
uint32_t VarArgSize) {
assert(Func->hasThisPointer());
assert(Func->isVirtual());
size_t ArgSize = Func->getArgSize() + VarArgSize;
size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);

const CXXRecordDecl *DynamicDecl = nullptr;
{
Pointer TypePtr = ThisPtr;
while (TypePtr.isBaseClass())
TypePtr = TypePtr.getBase();

QualType DynamicType = TypePtr.getType();
if (DynamicType->isPointerType() || DynamicType->isReferenceType())
DynamicDecl = DynamicType->getPointeeCXXRecordDecl();
else
DynamicDecl = DynamicType->getAsCXXRecordDecl();
}
assert(DynamicDecl);

const auto *StaticDecl = cast<CXXRecordDecl>(Func->getParentDecl());
const auto *InitialFunction = cast<CXXMethodDecl>(Func->getDecl());
const CXXMethodDecl *Overrider = S.getContext().getOverridingFunction(
DynamicDecl, StaticDecl, InitialFunction);

if (Overrider != InitialFunction) {
// DR1872: An instantiated virtual constexpr function can't be called in a
// constant expression (prior to C++20). We can still constant-fold such a
// call.
if (!S.getLangOpts().CPlusPlus20 && Overrider->isVirtual()) {
const Expr *E = S.Current->getExpr(OpPC);
S.CCEDiag(E, diag::note_constexpr_virtual_call) << E->getSourceRange();
}

Func = S.getContext().getOrCreateFunction(Overrider);

const CXXRecordDecl *ThisFieldDecl =
ThisPtr.getFieldDesc()->getType()->getAsCXXRecordDecl();
if (Func->getParentDecl()->isDerivedFrom(ThisFieldDecl)) {
// If the function we call is further DOWN the hierarchy than the
// FieldDesc of our pointer, just go up the hierarchy of this field
// the furthest we can go.
while (ThisPtr.isBaseClass())
ThisPtr = ThisPtr.getBase();
}
}

if (!Call(S, OpPC, Func, VarArgSize))
return false;

// Covariant return types. The return type of Overrider is a pointer
// or reference to a class type.
if (Overrider != InitialFunction &&
Overrider->getReturnType()->isPointerOrReferenceType() &&
InitialFunction->getReturnType()->isPointerOrReferenceType()) {
QualType OverriderPointeeType =
Overrider->getReturnType()->getPointeeType();
QualType InitialPointeeType =
InitialFunction->getReturnType()->getPointeeType();
// We've called Overrider above, but calling code expects us to return what
// InitialFunction returned. According to the rules for covariant return
// types, what InitialFunction returns needs to be a base class of what
// Overrider returns. So, we need to do an upcast here.
unsigned Offset = S.getContext().collectBaseOffset(
InitialPointeeType->getAsRecordDecl(),
OverriderPointeeType->getAsRecordDecl());
return GetPtrBasePop(S, OpPC, Offset);
}

return true;
}

bool CallBI(InterpState &S, CodePtr &PC, const Function *Func,
const CallExpr *CE) {
auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);

InterpFrame *FrameBefore = S.Current;
S.Current = NewFrame.get();

if (InterpretBuiltin(S, PC, Func, CE)) {
NewFrame.release();
return true;
}
S.Current = FrameBefore;
return false;
}

bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
const CallExpr *CE) {
const FunctionPointer &FuncPtr = S.Stk.pop<FunctionPointer>();

const Function *F = FuncPtr.getFunction();
if (!F) {
const auto *E = cast<CallExpr>(S.Current->getExpr(OpPC));
S.FFDiag(E, diag::note_constexpr_null_callee)
<< const_cast<Expr *>(E->getCallee()) << E->getSourceRange();
return false;
}

if (!FuncPtr.isValid() || !F->getDecl())
return Invalid(S, OpPC);

assert(F);

// This happens when the call expression has been cast to
// something else, but we don't support that.
if (S.Ctx.classify(F->getDecl()->getReturnType()) !=
S.Ctx.classify(CE->getType()))
return false;

// Check argument nullability state.
if (F->hasNonNullAttr()) {
if (!CheckNonNullArgs(S, OpPC, F, CE, ArgSize))
return false;
}

assert(ArgSize >= F->getWrittenArgSize());
uint32_t VarArgSize = ArgSize - F->getWrittenArgSize();

// We need to do this explicitly here since we don't have the necessary
// information to do it automatically.
if (F->isThisPointerExplicit())
VarArgSize -= align(primSize(PT_Ptr));

if (F->isVirtual())
return CallVirt(S, OpPC, F, VarArgSize);

return Call(S, OpPC, F, VarArgSize);
}

bool Interpret(InterpState &S, APValue &Result) {
// The current stack frame when we started Interpret().
// This is being used by the ops to determine wheter
Expand Down
Loading