85 changes: 85 additions & 0 deletions clang/docs/RealtimeSanitizer.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
=================
RealtimeSanitizer
=================

.. contents::
:local:

Introduction
============
RealtimeSanitizer (a.k.a. RTSan) is a real-time safety testing tool for C and C++
projects. RTSan can be used to detect real-time violations, i.e. calls to methods
that are not safe for use in functions with deterministic runtime requirements.
RTSan considers any function marked with the ``[[clang::nonblocking]]`` attribute
to be a real-time function. If RTSan detects a call to ``malloc``, ``free``,
``pthread_mutex_lock``, or anything else that could have a non-deterministic
execution time in a function marked ``[[clang::nonblocking]]``
RTSan raises an error.

The runtime slowdown introduced by RealtimeSanitizer is negligible.

How to build
============

Build LLVM/Clang with `CMake <https://llvm.org/docs/CMake.html>` and enable the
``compiler-rt`` runtime. An example CMake configuration that will allow for the
use/testing of RealtimeSanitizer:

.. code-block:: console
$ cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="clang" -DLLVM_ENABLE_RUNTIMES="compiler-rt" <path to source>/llvm
Usage
=====

There are two requirements:

1. The code must be compiled with the ``-fsanitize=realtime`` flag.
2. Functions that are subject to real-time constraints must be marked
with the ``[[clang::nonblocking]]`` attribute.

Typically, these attributes should be added onto the functions that are entry
points for threads with real-time priority. These threads are subject to a fixed
callback time, such as audio callback threads or rendering loops in video game
code.

.. code-block:: console
% cat example_realtime_violation.cpp
#include <vector>
void violation() [[clang::nonblocking]]{
std::vector<float> v;
v.resize(100);
}
int main() {
violation();
return 0;
}
# Compile and link
% clang++ -fsanitize=realtime -g example_realtime_violation.cpp
If a real-time safety violation is detected in a ``[[clang::nonblocking]]``
context, or any function invoked by that function, the program will exit with a
non-zero exit code.

.. code-block:: console
% clang++ -fsanitize=realtime -g example_realtime_violation.cpp
% ./a.out
Real-time violation: intercepted call to real-time unsafe function `malloc` in real-time context! Stack trace:
#0 0x000102893034 in __rtsan::PrintStackTrace() rtsan_stack.cpp:45
#1 0x000102892e64 in __rtsan::Context::ExpectNotRealtime(char const*) rtsan_context.cpp:78
#2 0x00010289397c in malloc rtsan_interceptors.cpp:286
#3 0x000195bd7bd0 in operator new(unsigned long)+0x1c (libc++abi.dylib:arm64+0x16bd0)
#4 0x5c7f00010230f07c (<unknown module>)
#5 0x00010230f058 in std::__1::__libcpp_allocate[abi:ue170006](unsigned long, unsigned long) new:324
#6 0x00010230effc in std::__1::allocator<float>::allocate[abi:ue170006](unsigned long) allocator.h:114
... snip ...
#10 0x00010230e4bc in std::__1::vector<float, std::__1::allocator<float>>::__append(unsigned long) vector:1162
#11 0x00010230dcdc in std::__1::vector<float, std::__1::allocator<float>>::resize(unsigned long) vector:1981
#12 0x00010230dc28 in violation() main.cpp:5
#13 0x00010230dd64 in main main.cpp:9
#14 0x0001958960dc (<unknown module>)
#15 0x2f557ffffffffffc (<unknown module>)
81 changes: 59 additions & 22 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ C++ Specific Potentially Breaking Changes
ABI Changes in This Version
---------------------------

- Fixed Microsoft name mangling of placeholder, auto and decltype(auto), return types for MSVC 1920+. This change resolves incompatibilities with code compiled by MSVC 1920+ but will introduce incompatibilities with code compiled by earlier versions of Clang unless such code is built with the compiler option -fms-compatibility-version=19.14 to imitate the MSVC 1914 mangling behavior.

AST Dumping Potentially Breaking Changes
----------------------------------------

Expand Down Expand Up @@ -107,19 +109,6 @@ 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.

C++17 Feature Support
^^^^^^^^^^^^^^^^^^^^^

C++14 Feature Support
^^^^^^^^^^^^^^^^^^^^^

C++20 Feature Support
^^^^^^^^^^^^^^^^^^^^^

C++23 Feature Support
^^^^^^^^^^^^^^^^^^^^^
- Removed the restriction to literal types in constexpr functions in C++23 mode.

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

Expand All @@ -131,6 +120,16 @@ C++2c Feature Support

- Implemented `P2893R3 Variadic Friends <https://wg21.link/P2893>`_

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

C++23 Feature Support
^^^^^^^^^^^^^^^^^^^^^
- Removed the restriction to literal types in constexpr functions in C++23 mode.

C++20 Feature Support
^^^^^^^^^^^^^^^^^^^^^


Resolutions to C++ Defect Reports
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down Expand Up @@ -174,14 +173,23 @@ Non-comprehensive list of changes in this release
New Compiler Flags
------------------

- The ``-fc++-static-destructors={all,thread-local,none}`` flag was
added to control which C++ variables have static destructors
registered: all (the default) does so for all variables, thread-local
only for thread-local variables, and none (which corresponds to the
existing ``-fno-c++-static-destructors`` flag) skips all static
destructors registration.

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

- ``-fheinous-gnu-extensions`` is deprecated; it is now equivalent to
specifying ``-Wno-error=invalid-gnu-asm-cast`` and may be removed in the
future.

Modified Compiler Flags
-----------------------

- The compiler flag `-fbracket-depth` default value is increased from 256 to 2048.

- The ``-ffp-model`` option has been updated to enable a more limited set of
optimizations when the ``fast`` argument is used and to accept a new argument,
``aggressive``. The behavior of ``-ffp-model=aggressive`` is equivalent
Expand Down Expand Up @@ -239,6 +247,20 @@ Improvements to Clang's diagnostics

- Clang now diagnoses when the result of a [[nodiscard]] function is discarded after being cast in C. Fixes #GH104391.

- Don't emit duplicated dangling diagnostics. (#GH93386).

- Improved diagnostic when trying to befriend a concept. (#GH45182).

- Added the ``-Winvalid-gnu-asm-cast`` diagnostic group to control warnings
about use of "noop" casts for lvalues (a GNU extension). This diagnostic is
a warning which defaults to being an error, is enabled by default, and is
also controlled by the now-deprecated ``-fheinous-gnu-extensions`` flag.

- Added the ``-Wdecls-in-multiple-modules`` option to assist users to identify
multiple declarations in different modules, which is the major reason of the slow
compilation speed with modules. This warning is disabled by default and it needs
to be explicitly enabled or by ``-Weverything``.

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

Expand Down Expand Up @@ -292,6 +314,10 @@ Bug Fixes to C++ Support
- Correctly check constraints of explicit instantiations of member functions. (#GH46029)
- Fixed an assertion failure about a constraint of a friend function template references to a value with greater
template depth than the friend function template. (#GH98258)
- Clang now rebuilds the template parameters of out-of-line declarations and specializations in the context
of the current instantiation in all cases.
- Fix evaluation of the index of dependent pack indexing expressions/types specifiers (#GH105900)
- Correctly handle subexpressions of an immediate invocation in the presence of implicit casts. (#GH105558)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -448,31 +474,42 @@ Moved checkers

Sanitizers
----------
- Introduced Realtime Sanitizer, activated by using the -fsanitize=realtime
flag. This sanitizer detects unsafe system library calls, such as memory
allocations and mutex locks. If any such function is called during invocation
of a function marked with the ``[[clang::nonblocking]]`` attribute, an error
is printed to the console and the process exits non-zero.

- Added the ``-fsanitize-undefined-ignore-overflow-pattern`` flag which can be
used to disable specific overflow-dependent code patterns. The supported
patterns are: ``add-overflow-test``, ``negated-unsigned-const``, and
``post-decr-while``. The sanitizer instrumentation can be toggled off for all
available patterns by specifying ``all``. Conversely, you can disable all
exclusions with ``none``.
patterns are: ``add-signed-overflow-test``, ``add-unsigned-overflow-test``,
``negated-unsigned-const``, and ``unsigned-post-decr-while``. The sanitizer
instrumentation can be toggled off for all available patterns by specifying
``all``. Conversely, you may disable all exclusions with ``none`` which is
the default.

.. code-block:: c++

/// specified with ``-fsanitize-undefined-ignore-overflow-pattern=add-overflow-test``
/// specified with ``-fsanitize-undefined-ignore-overflow-pattern=add-unsigned-overflow-test``
int common_overflow_check_pattern(unsigned base, unsigned offset) {
if (base + offset < base) { /* ... */ } // The pattern of `a + b < a`, and other re-orderings, won't be instrumented
}
/// specified with ``-fsanitize-undefined-ignore-overflow-pattern=add-signed-overflow-test``
int common_overflow_check_pattern_signed(signed int base, signed int offset) {
if (base + offset < base) { /* ... */ } // The pattern of `a + b < a`, and other re-orderings, won't be instrumented
}
/// specified with ``-fsanitize-undefined-ignore-overflow-pattern=negated-unsigned-const``
void negation_overflow() {
unsigned long foo = -1UL; // No longer causes a negation overflow warning
unsigned long bar = -2UL; // and so on...
}

/// specified with ``-fsanitize-undefined-ignore-overflow-pattern=post-decr-while``
/// specified with ``-fsanitize-undefined-ignore-overflow-pattern=unsigned-post-decr-while``
void while_post_decrement() {
unsigned char count = 16;
while (count--) { /* ... */} // No longer causes unsigned-integer-overflow sanitizer to trip
while (count--) { /* ... */ } // No longer causes unsigned-integer-overflow sanitizer to trip
}
Many existing projects have a large amount of these code patterns present.
Expand Down
73 changes: 4 additions & 69 deletions clang/docs/StandardCPlusPlusModules.rst
Original file line number Diff line number Diff line change
Expand Up @@ -894,6 +894,9 @@ approach:
Reducing the duplication from textual includes is what improves compile-time
performance.

To help users to identify such issues, we add a warning ``-Wdecls-in-multiple-modules``.
This warning is disabled by default and it needs to be explicitly enabled or by ``-Weverything``.

Transitioning to modules
------------------------

Expand Down Expand Up @@ -1297,74 +1300,6 @@ A high-level overview of support for standards features, including modules, can
be found on the `C++ Feature Status <https://clang.llvm.org/cxx_status.html>`_
page.

Missing VTables for classes attached to modules
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Now the compiler may miss emitting the definition of vtables
for classes attached to modules, if the definition of the class
doesn't contain any key function in that module units
(The key function is the first non-pure virtual function that is
not inline at the point of class definition.)

(Note: technically, the key function is not a thing for modules.
We use the concept here for convinient.)

For example,

.. code-block:: c++

// layer1.cppm
export module foo:layer1;
struct Fruit {
virtual ~Fruit() = default;
virtual void eval() = 0;
};
struct Banana : public Fruit {
Banana() {}
void eval() override;
};

// layer2.cppm
export module foo:layer2;
import :layer1;
export void layer2_fun() {
Banana *b = new Banana();
b->eval();
}
void Banana::eval() {
}
For the above example, we can't find the definition for the vtable of
class ``Banana`` in any object files.

The expected behavior is, for dynamic classes attached to named modules,
the vtable should always be emitted to the module units the class attaches
to.

To workaround the problem, users can add the key function manually in the
corresponding module units. e.g.,

.. code-block:: c++

// layer1.cppm
export module foo:layer1;
struct Fruit {
virtual ~Fruit() = default;
virtual void eval() = 0;
};
struct Banana : public Fruit {
// Hack a key function to hint the compiler to emit the virtual table.
virtual void anchor();

Banana() {}
void eval() override;
};

void Banana::anchor() {}

This is tracked by
`#70585 <https://github.com/llvm/llvm-project/issues/70585>`_.

Including headers after import is not well-supported
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down Expand Up @@ -1436,7 +1371,7 @@ non-module unit depending on the definition of some macros. However, this usage
is forbidden by P1857R3 which is not yet implemented in Clang. This means that
is possible to write invalid modules which will no longer be accepted once
P1857R3 is implemented. This is tracked by
`#56917 <https://github.com/llvm/llvm-project/issues/56917>`_.
`#54047 <https://github.com/llvm/llvm-project/issues/54047>`_.

Until then, it is recommended not to mix macros with module declarations.

Expand Down
37 changes: 30 additions & 7 deletions clang/docs/UndefinedBehaviorSanitizer.rst
Original file line number Diff line number Diff line change
Expand Up @@ -314,26 +314,49 @@ Currently, this option supports three overflow-dependent code idioms:
unsigned long foo = -1UL; // No longer causes a negation overflow warning
unsigned long bar = -2UL; // and so on...

``post-decr-while``
``unsigned-post-decr-while``

.. code-block:: c++

/// -fsanitize-undefined-ignore-overflow-pattern=post-decr-while
/// -fsanitize-undefined-ignore-overflow-pattern=unsigned-post-decr-while
unsigned char count = 16;
while (count--) { /* ... */ } // No longer causes unsigned-integer-overflow sanitizer to trip
``add-overflow-test``
``add-signed-overflow-test,add-unsigned-overflow-test``

.. code-block:: c++

/// -fsanitize-undefined-ignore-overflow-pattern=add-overflow-test
/// -fsanitize-undefined-ignore-overflow-pattern=add-(signed|unsigned)-overflow-test
if (base + offset < base) { /* ... */ } // The pattern of `a + b < a`, and other re-orderings,
// won't be instrumented (same for signed types)
// won't be instrumented (signed or unsigned types)
.. list-table:: Overflow Pattern Types
:widths: 30 50
:header-rows: 1

* - Pattern
- Sanitizer
* - negated-unsigned-const
- unsigned-integer-overflow
* - unsigned-post-decr-while
- unsigned-integer-overflow
* - add-unsigned-overflow-test
- unsigned-integer-overflow
* - add-signed-overflow-test
- signed-integer-overflow



Note: ``add-signed-overflow-test`` suppresses only the check for Undefined
Behavior. Eager Undefined Behavior optimizations are still possible. One may
remedy this with ``-fwrapv`` or ``-fno-strict-overflow``.

You can enable all exclusions with
``-fsanitize-undefined-ignore-overflow-pattern=all`` or disable all exclusions
with ``-fsanitize-undefined-ignore-overflow-pattern=none``. Specifying ``none``
has precedence over other values.
with ``-fsanitize-undefined-ignore-overflow-pattern=none``. If
``-fsanitize-undefined-ignore-overflow-pattern`` is not specified ``none`` is
implied. Specifying ``none`` alongside other values also implies ``none`` as
``none`` has precedence over other values -- including ``all``.

Issue Suppression
=================
Expand Down
2 changes: 2 additions & 0 deletions clang/docs/UsersManual.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2068,6 +2068,8 @@ are listed below.
integrity.
- ``-fsanitize=safe-stack``: :doc:`safe stack <SafeStack>`
protection against stack-based memory corruption errors.
- ``-fsanitize=realtime``: :doc:`RealtimeSanitizer`,
a real-time safety checker.

There are more fine-grained checks available: see
the :ref:`list <ubsan-checks>` of specific kinds of
Expand Down
1 change: 1 addition & 0 deletions clang/docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Using Clang as a Compiler
UndefinedBehaviorSanitizer
DataFlowSanitizer
LeakSanitizer
RealtimeSanitizer
SanitizerCoverage
SanitizerStats
SanitizerSpecialCaseList
Expand Down
13 changes: 11 additions & 2 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -2200,6 +2200,15 @@ def BTFTypeTag : TypeAttr {
let LangOpts = [COnly];
}

def BPFFastCall : InheritableAttr,
TargetSpecificAttr<TargetBPF> {
let Spellings = [Clang<"bpf_fastcall">];
let Subjects = SubjectList<[FunctionLike]>;
let Documentation = [BPFFastCallDocs];
let LangOpts = [COnly];
let SimpleHandler = 1;
}

def WebAssemblyExportName : InheritableAttr,
TargetSpecificAttr<TargetWebAssembly> {
let Spellings = [Clang<"export_name">];
Expand Down Expand Up @@ -4529,7 +4538,7 @@ def HLSLSV_GroupIndex: HLSLAnnotationAttr {

def HLSLResourceBinding: InheritableAttr {
let Spellings = [HLSLAnnotation<"register">];
let Subjects = SubjectList<[HLSLBufferObj, ExternalGlobalVar]>;
let Subjects = SubjectList<[HLSLBufferObj, ExternalGlobalVar], ErrorDiag>;
let LangOpts = [HLSL];
let Args = [StringArgument<"Slot">, StringArgument<"Space", 1>];
let Documentation = [HLSLResourceBindingDocs];
Expand Down Expand Up @@ -4613,7 +4622,7 @@ def HLSLROV : InheritableAttr {

def HLSLResourceClass : InheritableAttr {
let Spellings = [CXX11<"hlsl", "resource_class">];
let Subjects = SubjectList<[Struct]>;
let Subjects = SubjectList<[Field]>;
let LangOpts = [HLSL];
let Args = [
EnumArgument<"ResourceClass", "llvm::hlsl::ResourceClass",
Expand Down
19 changes: 19 additions & 0 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -2345,6 +2345,25 @@ section.
}];
}

def BPFFastCallDocs : Documentation {
let Category = DocCatType;
let Content = [{
Functions annotated with this attribute are likely to be inlined by BPF JIT.
It is assumed that inlined implementation uses less caller saved registers,
than a regular function.
Specifically, the following registers are likely to be preserved:
- ``R0`` if function return value is ``void``;
- ``R2-R5` if function takes 1 argument;
- ``R3-R5` if function takes 2 arguments;
- ``R4-R5` if function takes 3 arguments;
- ``R5`` if function takes 4 arguments;

For such functions Clang generates code pattern that allows BPF JIT
to recognize and remove unnecessary spills and fills of the preserved
registers.
}];
}

def MipsInterruptDocs : Documentation {
let Category = DocCatFunction;
let Heading = "interrupt (MIPS)";
Expand Down
22 changes: 11 additions & 11 deletions clang/include/clang/Basic/BuiltinsWebAssembly.def
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,10 @@ TARGET_BUILTIN(__builtin_wasm_min_f64x2, "V2dV2dV2d", "nc", "simd128")
TARGET_BUILTIN(__builtin_wasm_max_f64x2, "V2dV2dV2d", "nc", "simd128")
TARGET_BUILTIN(__builtin_wasm_pmin_f64x2, "V2dV2dV2d", "nc", "simd128")
TARGET_BUILTIN(__builtin_wasm_pmax_f64x2, "V2dV2dV2d", "nc", "simd128")
TARGET_BUILTIN(__builtin_wasm_min_f16x8, "V8hV8hV8h", "nc", "half-precision")
TARGET_BUILTIN(__builtin_wasm_max_f16x8, "V8hV8hV8h", "nc", "half-precision")
TARGET_BUILTIN(__builtin_wasm_pmin_f16x8, "V8hV8hV8h", "nc", "half-precision")
TARGET_BUILTIN(__builtin_wasm_pmax_f16x8, "V8hV8hV8h", "nc", "half-precision")
TARGET_BUILTIN(__builtin_wasm_min_f16x8, "V8hV8hV8h", "nc", "fp16")
TARGET_BUILTIN(__builtin_wasm_max_f16x8, "V8hV8hV8h", "nc", "fp16")
TARGET_BUILTIN(__builtin_wasm_pmin_f16x8, "V8hV8hV8h", "nc", "fp16")
TARGET_BUILTIN(__builtin_wasm_pmax_f16x8, "V8hV8hV8h", "nc", "fp16")

TARGET_BUILTIN(__builtin_wasm_ceil_f32x4, "V4fV4f", "nc", "simd128")
TARGET_BUILTIN(__builtin_wasm_floor_f32x4, "V4fV4f", "nc", "simd128")
Expand Down Expand Up @@ -170,8 +170,8 @@ TARGET_BUILTIN(__builtin_wasm_relaxed_madd_f32x4, "V4fV4fV4fV4f", "nc", "relaxed
TARGET_BUILTIN(__builtin_wasm_relaxed_nmadd_f32x4, "V4fV4fV4fV4f", "nc", "relaxed-simd")
TARGET_BUILTIN(__builtin_wasm_relaxed_madd_f64x2, "V2dV2dV2dV2d", "nc", "relaxed-simd")
TARGET_BUILTIN(__builtin_wasm_relaxed_nmadd_f64x2, "V2dV2dV2dV2d", "nc", "relaxed-simd")
TARGET_BUILTIN(__builtin_wasm_relaxed_madd_f16x8, "V8hV8hV8hV8h", "nc", "half-precision")
TARGET_BUILTIN(__builtin_wasm_relaxed_nmadd_f16x8, "V8hV8hV8hV8h", "nc", "half-precision")
TARGET_BUILTIN(__builtin_wasm_relaxed_madd_f16x8, "V8hV8hV8hV8h", "nc", "fp16")
TARGET_BUILTIN(__builtin_wasm_relaxed_nmadd_f16x8, "V8hV8hV8hV8h", "nc", "fp16")

TARGET_BUILTIN(__builtin_wasm_relaxed_laneselect_i8x16, "V16ScV16ScV16ScV16Sc", "nc", "relaxed-simd")
TARGET_BUILTIN(__builtin_wasm_relaxed_laneselect_i16x8, "V8sV8sV8sV8s", "nc", "relaxed-simd")
Expand All @@ -197,11 +197,11 @@ TARGET_BUILTIN(__builtin_wasm_relaxed_dot_i8x16_i7x16_add_s_i32x4, "V4iV16ScV16S
TARGET_BUILTIN(__builtin_wasm_relaxed_dot_bf16x8_add_f32_f32x4, "V4fV8UsV8UsV4f", "nc", "relaxed-simd")

// Half-Precision (fp16)
TARGET_BUILTIN(__builtin_wasm_loadf16_f32, "fh*", "nU", "half-precision")
TARGET_BUILTIN(__builtin_wasm_storef16_f32, "vfh*", "n", "half-precision")
TARGET_BUILTIN(__builtin_wasm_splat_f16x8, "V8hf", "nc", "half-precision")
TARGET_BUILTIN(__builtin_wasm_extract_lane_f16x8, "fV8hi", "nc", "half-precision")
TARGET_BUILTIN(__builtin_wasm_replace_lane_f16x8, "V8hV8hif", "nc", "half-precision")
TARGET_BUILTIN(__builtin_wasm_loadf16_f32, "fh*", "nU", "fp16")
TARGET_BUILTIN(__builtin_wasm_storef16_f32, "vfh*", "n", "fp16")
TARGET_BUILTIN(__builtin_wasm_splat_f16x8, "V8hf", "nc", "fp16")
TARGET_BUILTIN(__builtin_wasm_extract_lane_f16x8, "fV8hi", "nc", "fp16")
TARGET_BUILTIN(__builtin_wasm_replace_lane_f16x8, "V8hV8hif", "nc", "fp16")

// Reference Types builtins
// Some builtins are custom type-checked - see 't' as part of the third argument,
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/CodeGenOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ VALUE_CODEGENOPT(Name, Bits, Default)

CODEGENOPT(DisableIntegratedAS, 1, 0) ///< -no-integrated-as
CODEGENOPT(Crel, 1, 0) ///< -Wa,--crel
CODEGENOPT(ImplicitMapSyms, 1, 0) ///< -Wa,-mmapsyms=implicit
CODEGENOPT(AsmVerbose , 1, 0) ///< -dA, -fverbose-asm.
CODEGENOPT(PreserveAsmComments, 1, 1) ///< -dA, -fno-preserve-as-comments.
CODEGENOPT(AssumeSaneOperatorNew , 1, 1) ///< implicit __attribute__((malloc)) operator new
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Basic/DiagnosticASTKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,8 @@ def note_constexpr_new : Note<
def note_constexpr_new_non_replaceable : Note<
"call to %select{placement|class-specific}0 %1">;
def note_constexpr_new_placement : Note<
"this placement new expression is not yet supported in constant expressions">;
"this placement new expression is not supported in constant expressions "
"%select{|before C++2c}0">;
def note_constexpr_placement_new_wrong_type : Note<
"placement new would change type of storage from %0 to %1">;
def note_constexpr_new_negative : Note<
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticGroups.td
Original file line number Diff line number Diff line change
Expand Up @@ -1547,6 +1547,9 @@ def DXILValidation : DiagGroup<"dxil-validation">;
// Warning for HLSL API availability
def HLSLAvailability : DiagGroup<"hlsl-availability">;

// Warnings for legacy binding behavior
def LegacyConstantRegisterBinding : DiagGroup<"legacy-constant-register-binding">;

// Warnings and notes related to const_var_decl_type attribute checks
def ReadOnlyPlacementChecks : DiagGroup<"read-only-types">;

Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,9 @@ def warn_cxx23_variadic_friends : Warning<
"variadic 'friend' declarations are incompatible with C++ standards before C++2c">,
DefaultIgnore, InGroup<CXXPre26Compat>;

def err_friend_concept : Error<
"friend declaration cannot be a concept">;

// C++11 default member initialization
def ext_nonstatic_member_init : ExtWarn<
"default member initializer for non-static data member is a C++11 "
Expand Down
16 changes: 9 additions & 7 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -9365,9 +9365,6 @@ let CategoryName = "Inline Assembly Issue" in {
"invalid input size for constraint '%0'">;
def err_asm_invalid_output_size : Error<
"invalid output size for constraint '%0'">;
def err_invalid_asm_cast_lvalue : Error<
"invalid use of a cast in a inline asm context requiring an lvalue: "
"remove the cast or build with -fheinous-gnu-extensions">;
def err_invalid_asm_value_for_constraint
: Error <"value '%0' out of range for constraint '%1'">;
def err_asm_non_addr_value_in_memory_constraint : Error <
Expand All @@ -9381,9 +9378,8 @@ let CategoryName = "Inline Assembly Issue" in {
def warn_asm_label_on_auto_decl : Warning<
"ignored asm label '%0' on automatic variable">;
def warn_invalid_asm_cast_lvalue : Warning<
"invalid use of a cast in an inline asm context requiring an lvalue: "
"accepted due to -fheinous-gnu-extensions, but clang may remove support "
"for this in the future">;
"invalid use of a cast in an inline asm context requiring an lvalue">,
InGroup<DiagGroup<"invalid-gnu-asm-cast">>, DefaultError;
def warn_asm_mismatched_size_modifier : Warning<
"value size does not match register size specified by the constraint "
"and modifier">,
Expand Down Expand Up @@ -12352,7 +12348,13 @@ def err_hlsl_missing_semantic_annotation : Error<
def err_hlsl_init_priority_unsupported : Error<
"initializer priorities are not supported in HLSL">;

def err_hlsl_unsupported_register_type : Error<"invalid resource class specifier '%0' used; expected 'b', 's', 't', or 'u'">;
def warn_hlsl_user_defined_type_missing_member: Warning<"binding type '%select{t|u|b|s|c}0' only applies to types containing %select{SRV resources|UAV resources|constant buffer resources|sampler state|numeric types}0">, InGroup<LegacyConstantRegisterBinding>;
def err_hlsl_binding_type_mismatch: Error<"binding type '%select{t|u|b|s|c}0' only applies to %select{SRV resources|UAV resources|constant buffer resources|sampler state|numeric variables in the global scope}0">;
def err_hlsl_binding_type_invalid: Error<"binding type '%0' is invalid">;
def err_hlsl_duplicate_register_annotation: Error<"binding type '%select{t|u|b|s|c|i}0' cannot be applied more than once">;
def warn_hlsl_register_type_c_packoffset: Warning<"binding type 'c' ignored in buffer declaration. Did you mean 'packoffset'?">, InGroup<LegacyConstantRegisterBinding>, DefaultError;
def warn_hlsl_deprecated_register_type_b: Warning<"binding type 'b' only applies to constant buffers. The 'bool constant' binding type is no longer supported">, InGroup<LegacyConstantRegisterBinding>, DefaultError;
def warn_hlsl_deprecated_register_type_i: Warning<"binding type 'i' ignored. The 'integer constant' binding type is no longer supported">, InGroup<LegacyConstantRegisterBinding>, DefaultError;
def err_hlsl_unsupported_register_number : Error<"register number should be an integer">;
def err_hlsl_expected_space : Error<"invalid space specifier '%0' used; expected 'space' followed by an integer, like space1">;
def warn_hlsl_packoffset_mix : Warning<"cannot mix packoffset elements with nonpackoffset elements in a cbuffer">,
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/DiagnosticSerializationKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,12 @@ def warn_module_system_bit_conflict : Warning<
"as a non-system module; any difference in diagnostic options will be ignored">,
InGroup<ModuleConflict>;

def warn_decls_in_multiple_modules : Warning<
"declaration %0 is detected to be defined in multiple module units, first is from '%1' and second is from '%2'; "
"the compiler may not be good at merging the definitions. ">,
InGroup<DiagGroup<"decls-in-multiple-modules">>,
DefaultIgnore;

def err_failed_to_find_module_file : Error<
"failed to find module file for module '%0'">;
} // let CategoryName
Expand Down
5 changes: 3 additions & 2 deletions clang/include/clang/Basic/LangOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,6 @@ LANGOPT(POSIXThreads , 1, 0, "POSIX thread support")
LANGOPT(Blocks , 1, 0, "blocks extension to C")
BENIGN_LANGOPT(EmitAllDecls , 1, 0, "emitting all declarations")
LANGOPT(MathErrno , 1, 1, "errno in math functions")
BENIGN_LANGOPT(HeinousExtensions , 1, 0, "extensions that we really don't like and may be ripped out at any time")
LANGOPT(Modules , 1, 0, "modules semantics")
COMPATIBLE_LANGOPT(CPlusPlusModules, 1, 0, "C++ modules syntax")
LANGOPT(SkipODRCheckInGMF, 1, 0, "Skip ODR checks for decls in the global module fragment")
Expand Down Expand Up @@ -465,7 +464,9 @@ LANGOPT(FixedPoint, 1, 0, "fixed point types")
LANGOPT(PaddingOnUnsignedFixedPoint, 1, 0,
"unsigned fixed point types having one extra padding bit")

LANGOPT(RegisterStaticDestructors, 1, 1, "Register C++ static destructors")
ENUM_LANGOPT(RegisterStaticDestructors, RegisterStaticDestructorsKind, 2,
RegisterStaticDestructorsKind::All,
"Register C++ static destructors")

LANGOPT(RegCall4, 1, 0, "Set __regcall4 as a default calling convention to respect __regcall ABI v.4")

Expand Down
18 changes: 15 additions & 3 deletions clang/include/clang/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -375,11 +375,13 @@ class LangOptionsBase {
/// Exclude all overflow patterns (below)
All = 1 << 1,
/// if (a + b < a)
AddOverflowTest = 1 << 2,
AddSignedOverflowTest = 1 << 2,
/// if (a + b < a)
AddUnsignedOverflowTest = 1 << 3,
/// -1UL
NegUnsignedConst = 1 << 3,
NegUnsignedConst = 1 << 4,
/// while (count--)
PostDecrInWhile = 1 << 4,
PostDecrInWhile = 1 << 5,
};

enum class DefaultVisiblityExportMapping {
Expand Down Expand Up @@ -456,6 +458,16 @@ class LangOptionsBase {
CX_None
};

/// Controls which variables have static destructors registered.
enum class RegisterStaticDestructorsKind {
/// Register static destructors for all variables.
All,
/// Register static destructors only for thread-local variables.
ThreadLocal,
/// Don't register static destructors for any variables.
None,
};

// Define simple language options (with no accessors).
#define LANGOPT(Name, Bits, Default, Description) unsigned Name : Bits;
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description)
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/Sanitizers.def
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ SANITIZER("thread", Thread)
// Numerical stability sanitizer.
SANITIZER("numerical", NumericalStability)

// RealtimeSanitizer
SANITIZER("realtime", Realtime)

// LeakSanitizer
SANITIZER("leak", Leak)

Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/TokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,9 @@ KEYWORD(out , KEYHLSL)
#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) KEYWORD(Name, KEYHLSL)
#include "clang/Basic/HLSLIntangibleTypes.def"

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

// OpenMP Type Traits
UNARY_EXPR_OR_TYPE_TRAIT(__builtin_omp_required_simd_align, OpenMPRequiredSimdAlign, KEYALL)

Expand Down
3 changes: 1 addition & 2 deletions clang/include/clang/Driver/Driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -379,8 +379,7 @@ class Driver {

/// Takes the path to a binary that's either in bin/ or lib/ and returns
/// the path to clang's resource directory.
static std::string GetResourcesPath(StringRef BinaryPath,
StringRef CustomResourceDir = "");
static std::string GetResourcesPath(StringRef BinaryPath);

Driver(StringRef ClangExecutable, StringRef TargetTriple,
DiagnosticsEngine &Diags, std::string Title = "clang LLVM compiler",
Expand Down
45 changes: 34 additions & 11 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -1011,6 +1011,8 @@ def Wwrite_strings : Flag<["-"], "Wwrite-strings">, Group<W_Group>,
Flags<[HelpHidden]>, Visibility<[ClangOption, CC1Option]>;
def Wno_write_strings : Flag<["-"], "Wno-write-strings">, Group<W_Group>,
Flags<[HelpHidden]>, Visibility<[ClangOption, CC1Option]>;
def Winvalid_gnu_asm_cast : Flag<["-"], "Winvalid-gnu-asm-cast">, Group<W_Group>,
Flags<[HelpHidden]>, Visibility<[ClangOption, CC1Option]>;
def W_Joined : Joined<["-"], "W">, Group<W_Group>,
Visibility<[ClangOption, CC1Option, CLOption, DXCOption, FC1Option, FlangOption]>,
MetaVarName<"<warning>">, HelpText<"Enable the specified warning">;
Expand Down Expand Up @@ -2300,11 +2302,18 @@ defm fixed_point : BoolFOption<"fixed-point",
PosFlag<SetTrue, [], [ClangOption, CC1Option], "Enable">,
NegFlag<SetFalse, [], [ClangOption], "Disable">,
BothFlags<[], [ClangOption], " fixed point types">>;
defm cxx_static_destructors : BoolFOption<"c++-static-destructors",
LangOpts<"RegisterStaticDestructors">, DefaultTrue,
NegFlag<SetFalse, [], [ClangOption, CC1Option],
"Disable C++ static destructor registration">,
PosFlag<SetTrue>>;
def cxx_static_destructors_EQ : Joined<["-"], "fc++-static-destructors=">, Group<f_Group>,
HelpText<"Controls which variables C++ static destructors are registered for">,
Values<"all,thread-local,none">,
NormalizedValues<["All", "ThreadLocal", "None"]>,
NormalizedValuesScope<"LangOptions::RegisterStaticDestructorsKind">,
MarshallingInfoEnum<LangOpts<"RegisterStaticDestructors">, "All">,
Visibility<[ClangOption, CC1Option]>;
def cxx_static_destructors : Flag<["-"], "fc++-static-destructors">, Group<f_Group>,
Alias<cxx_static_destructors_EQ>, AliasArgs<["all"]>;
def no_cxx_static_destructors : Flag<["-"], "fno-c++-static-destructors">, Group<f_Group>,
Alias<cxx_static_destructors_EQ>, AliasArgs<["none"]>,
HelpText<"Disable C++ static destructor registration">;
def fsymbol_partition_EQ : Joined<["-"], "fsymbol-partition=">, Group<f_Group>,
Visibility<[ClangOption, CC1Option]>,
MarshallingInfoString<CodeGenOpts<"SymbolPartition">>;
Expand Down Expand Up @@ -2568,7 +2577,7 @@ defm sanitize_stats : BoolOption<"f", "sanitize-stats",
def fsanitize_undefined_ignore_overflow_pattern_EQ : CommaJoined<["-"], "fsanitize-undefined-ignore-overflow-pattern=">,
HelpText<"Specify the overflow patterns to exclude from artihmetic sanitizer instrumentation">,
Visibility<[ClangOption, CC1Option]>,
Values<"none,all,add-overflow-test,negated-unsigned-const,post-decr-while">,
Values<"none,all,add-unsigned-overflow-test,add-signed-overflow-test,negated-unsigned-const,unsigned-post-decr-while">,
MarshallingInfoStringVector<LangOpts<"OverflowPatternExclusionValues">>;
def fsanitize_thread_memory_access : Flag<["-"], "fsanitize-thread-memory-access">,
Group<f_clang_Group>,
Expand Down Expand Up @@ -2761,9 +2770,13 @@ defm gnu89_inline : BoolFOption<"gnu89-inline",
NegFlag<SetFalse>>, ShouldParseIf<!strconcat("!", cplusplus.KeyPath)>;
def fgnu_runtime : Flag<["-"], "fgnu-runtime">, Group<f_Group>,
HelpText<"Generate output compatible with the standard GNU Objective-C runtime">;
// This used to be a standalone flag but is now mapped to
// -Wno-error=invalid-gnu-asm-cast, which is the only thing the flag used to
// control.
def fheinous_gnu_extensions : Flag<["-"], "fheinous-gnu-extensions">,
Visibility<[ClangOption, CC1Option]>,
MarshallingInfoFlag<LangOpts<"HeinousExtensions">>;
Alias<W_Joined>, AliasArgs<["no-error=invalid-gnu-asm-cast"]>,
HelpText<"(Deprecated) Controls whether '-Winvalid-gnu-asm-cast' defaults to "
"an error or a warning">;
def filelist : Separate<["-"], "filelist">, Flags<[LinkerInput]>,
Group<Link_Group>;
def : Flag<["-"], "findirect-virtual-calls">, Alias<fapple_kext>;
Expand Down Expand Up @@ -5033,8 +5046,8 @@ def mexception_handing : Flag<["-"], "mexception-handling">, Group<m_wasm_Featur
def mno_exception_handing : Flag<["-"], "mno-exception-handling">, Group<m_wasm_Features_Group>;
def mextended_const : Flag<["-"], "mextended-const">, Group<m_wasm_Features_Group>;
def mno_extended_const : Flag<["-"], "mno-extended-const">, Group<m_wasm_Features_Group>;
def mhalf_precision : Flag<["-"], "mhalf-precision">, Group<m_wasm_Features_Group>;
def mno_half_precision : Flag<["-"], "mno-half-precision">, Group<m_wasm_Features_Group>;
def mfp16 : Flag<["-"], "mfp16">, Group<m_wasm_Features_Group>;
def mno_fp16 : Flag<["-"], "mno-fp16">, Group<m_wasm_Features_Group>;
def mmultimemory : Flag<["-"], "mmultimemory">, Group<m_wasm_Features_Group>;
def mno_multimemory : Flag<["-"], "mno-multimemory">, Group<m_wasm_Features_Group>;
def mmultivalue : Flag<["-"], "mmultivalue">, Group<m_wasm_Features_Group>;
Expand Down Expand Up @@ -6155,6 +6168,10 @@ def mv8plus : Flag<["-"], "mv8plus">, Group<m_sparc_Features_Group>,
HelpText<"Enable V8+ mode, allowing use of 64-bit V9 instructions in 32-bit code">;
def mno_v8plus : Flag<["-"], "mno-v8plus">, Group<m_sparc_Features_Group>,
HelpText<"Disable V8+ mode">;
def mfix_gr712rc : Flag<["-"], "mfix-gr712rc">, Group<m_sparc_Features_Group>,
HelpText<"Enable workarounds for GR712RC errata">;
def mfix_ut700 : Flag<["-"], "mfix-ut700">, Group<m_sparc_Features_Group>,
HelpText<"Enable workarounds for UT700 errata">;
foreach i = 1 ... 7 in
def ffixed_g#i : Flag<["-"], "ffixed-g"#i>, Group<m_sparc_Features_Group>,
HelpText<"Reserve the G"#i#" register (SPARC only)">;
Expand Down Expand Up @@ -7138,6 +7155,12 @@ def massembler_fatal_warnings : Flag<["-"], "massembler-fatal-warnings">,
def crel : Flag<["--"], "crel">,
HelpText<"Enable CREL relocation format (ELF only)">,
MarshallingInfoFlag<CodeGenOpts<"Crel">>;
def mmapsyms_implicit : Flag<["-"], "mmapsyms=implicit">,
HelpText<"Allow mapping symbol at section beginning to be implicit, "
"lowering number of mapping symbols at the expense of some "
"portability. Recommended for projects that can build all their "
"object files using this option">,
MarshallingInfoFlag<CodeGenOpts<"ImplicitMapSyms">>;
def mrelax_relocations_no : Flag<["-"], "mrelax-relocations=no">,
HelpText<"Disable x86 relax relocations">,
MarshallingInfoNegativeFlag<CodeGenOpts<"X86RelaxRelocations">>;
Expand Down Expand Up @@ -7966,7 +7989,7 @@ def fapply_global_visibility_to_externs : Flag<["-"], "fapply-global-visibility-
MarshallingInfoFlag<LangOpts<"SetVisibilityForExternDecls">>;
def fbracket_depth : Separate<["-"], "fbracket-depth">,
HelpText<"Maximum nesting level for parentheses, brackets, and braces">,
MarshallingInfoInt<LangOpts<"BracketDepth">, "2048">;
MarshallingInfoInt<LangOpts<"BracketDepth">, "256">;
defm const_strings : BoolOption<"f", "const-strings",
LangOpts<"ConstStrings">, DefaultFalse,
PosFlag<SetTrue, [], [ClangOption, CC1Option], "Use">,
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Driver/SanitizerArgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ class SanitizerArgs {
bool needsNsanRt() const {
return Sanitizers.has(SanitizerKind::NumericalStability);
}
bool needsRtsanRt() const { return Sanitizers.has(SanitizerKind::Realtime); }

bool hasMemTag() const {
return hasMemtagHeap() || hasMemtagStack() || hasMemtagGlobals();
Expand Down
50 changes: 33 additions & 17 deletions clang/include/clang/Format/Format.h
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,7 @@ struct FormatStyle {

/// If the function declaration doesn't fit on a line,
/// allow putting all parameters of a function declaration onto
/// the next line even if ``BinPackParameters`` is ``false``.
/// the next line even if ``BinPackParameters`` is ``OnePerLine``.
/// \code
/// true:
/// void myFunction(
Expand Down Expand Up @@ -1192,20 +1192,36 @@ struct FormatStyle {
/// \version 3.7
bool BinPackArguments;

/// If ``false``, a function declaration's or function definition's
/// parameters will either all be on the same line or will have one line each.
/// \code
/// true:
/// void f(int aaaaaaaaaaaaaaaaaaaa, int aaaaaaaaaaaaaaaaaaaa,
/// int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {}
///
/// false:
/// void f(int aaaaaaaaaaaaaaaaaaaa,
/// int aaaaaaaaaaaaaaaaaaaa,
/// int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {}
/// \endcode
/// Different way to try to fit all parameters on a line.
enum BinPackParametersStyle : int8_t {
/// Bin-pack parameters.
/// \code
/// void f(int a, int bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,
/// int ccccccccccccccccccccccccccccccccccccccccccc);
/// \endcode
BPPS_BinPack,
/// Put all parameters on the current line if they fit.
/// Otherwise, put each one on its own line.
/// \code
/// void f(int a, int b, int c);
///
/// void f(int a,
/// int b,
/// int ccccccccccccccccccccccccccccccccccccc);
/// \endcode
BPPS_OnePerLine,
/// Always put each parameter on its own line.
/// \code
/// void f(int a,
/// int b,
/// int c);
/// \endcode
BPPS_AlwaysOnePerLine,
};

/// The bin pack parameters style to use.
/// \version 3.7
bool BinPackParameters;
BinPackParametersStyle BinPackParameters;

/// Styles for adding spacing around ``:`` in bitfield definitions.
enum BitFieldColonSpacingStyle : int8_t {
Expand Down Expand Up @@ -3414,7 +3430,7 @@ struct FormatStyle {
/// items into as few lines as possible when they go over ``ColumnLimit``.
///
/// If ``Auto`` (the default), delegates to the value in
/// ``BinPackParameters``. If that is ``true``, bin-packs Objective-C
/// ``BinPackParameters``. If that is ``BinPack``, bin-packs Objective-C
/// protocol conformance list items into as few lines as possible
/// whenever they go over ``ColumnLimit``.
///
Expand All @@ -3426,13 +3442,13 @@ struct FormatStyle {
/// onto individual lines whenever they go over ``ColumnLimit``.
///
/// \code{.objc}
/// Always (or Auto, if BinPackParameters=true):
/// Always (or Auto, if BinPackParameters==BinPack):
/// @interface ccccccccccccc () <
/// ccccccccccccc, ccccccccccccc,
/// ccccccccccccc, ccccccccccccc> {
/// }
///
/// Never (or Auto, if BinPackParameters=false):
/// Never (or Auto, if BinPackParameters!=BinPack):
/// @interface ddddddddddddd () <
/// ddddddddddddd,
/// ddddddddddddd,
Expand Down
4 changes: 3 additions & 1 deletion clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -3021,15 +3021,17 @@ class Parser : public CodeCompletionHandler {
SemaCodeCompletion::AttributeCompletion::None,
const IdentifierInfo *EnclosingScope = nullptr);

void MaybeParseHLSLAnnotations(Declarator &D,
bool MaybeParseHLSLAnnotations(Declarator &D,
SourceLocation *EndLoc = nullptr,
bool CouldBeBitField = false) {
assert(getLangOpts().HLSL && "MaybeParseHLSLAnnotations is for HLSL only");
if (Tok.is(tok::colon)) {
ParsedAttributes Attrs(AttrFactory);
ParseHLSLAnnotations(Attrs, EndLoc, CouldBeBitField);
D.takeAttributes(Attrs);
return true;
}
return false;
}

void MaybeParseHLSLAnnotations(ParsedAttributes &Attrs,
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Sema/SemaHLSL.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ class SemaHLSL : public SemaBase {
void handleParamModifierAttr(Decl *D, const ParsedAttr &AL);

bool CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);

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

} // namespace clang
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Serialization/ASTReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,12 @@ class ASTReader
/// performed deduplication.
llvm::SetVector<NamedDecl *> PendingMergedDefinitionsToDeduplicate;

/// The duplicated definitions in module units which are pending to be warned.
/// We need to delay it to wait for the loading of definitions since we don't
/// want to warn for forward declarations.
llvm::SmallVector<std::pair<Decl *, Decl *>>
PendingWarningForDuplicatedDefsInModuleUnits;

/// Read the record that describes the lexical contents of a DC.
bool ReadLexicalDeclContextStorage(ModuleFile &M,
llvm::BitstreamCursor &Cursor,
Expand Down
73 changes: 50 additions & 23 deletions clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -885,34 +885,60 @@ bool Compiler<Emitter>::VisitPointerArithBinOp(const BinaryOperator *E) {
if (!LT || !RT)
return false;

// Visit the given pointer expression and optionally convert to a PT_Ptr.
auto visitAsPointer = [&](const Expr *E, PrimType T) -> bool {
if (!this->visit(E))
return false;
if (T != PT_Ptr)
return this->emitDecayPtr(T, PT_Ptr, E);
return true;
};

if (LHS->getType()->isPointerType() && RHS->getType()->isPointerType()) {
if (Op != BO_Sub)
return false;

assert(E->getType()->isIntegerType());
if (!visit(RHS) || !visit(LHS))
if (!visitAsPointer(RHS, *RT) || !visitAsPointer(LHS, *LT))
return false;

return this->emitSubPtr(classifyPrim(E->getType()), E);
}

PrimType OffsetType;
if (LHS->getType()->isIntegerType()) {
if (!visit(RHS) || !visit(LHS))
if (!visitAsPointer(RHS, *RT))
return false;
if (!this->visit(LHS))
return false;
OffsetType = *LT;
} else if (RHS->getType()->isIntegerType()) {
if (!visit(LHS) || !visit(RHS))
if (!visitAsPointer(LHS, *LT))
return false;
if (!this->visit(RHS))
return false;
OffsetType = *RT;
} else {
return false;
}

if (Op == BO_Add)
return this->emitAddOffset(OffsetType, E);
else if (Op == BO_Sub)
return this->emitSubOffset(OffsetType, E);
// Do the operation and optionally transform to
// result pointer type.
if (Op == BO_Add) {
if (!this->emitAddOffset(OffsetType, E))
return false;

if (classifyPrim(E) != PT_Ptr)
return this->emitDecayPtr(PT_Ptr, classifyPrim(E), E);
return true;
} else if (Op == BO_Sub) {
if (!this->emitSubOffset(OffsetType, E))
return false;

if (classifyPrim(E) != PT_Ptr)
return this->emitDecayPtr(PT_Ptr, classifyPrim(E), E);
return true;
}

return false;
}
Expand Down Expand Up @@ -1318,14 +1344,15 @@ bool Compiler<Emitter>::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
template <class Emitter>
bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
const Expr *ArrayFiller, const Expr *E) {

QualType QT = E->getType();

if (const auto *AT = QT->getAs<AtomicType>())
QT = AT->getValueType();

if (QT->isVoidType())
if (QT->isVoidType()) {
if (Inits.size() == 0)
return true;
return this->emitInvalid(E);
}

// Handle discarding first.
if (DiscardResult) {
Expand Down Expand Up @@ -3238,9 +3265,6 @@ template <class Emitter> bool Compiler<Emitter>::discard(const Expr *E) {
}

template <class Emitter> bool Compiler<Emitter>::delegate(const Expr *E) {
if (E->containsErrors())
return this->emitError(E);

// We're basically doing:
// OptionScope<Emitter> Scope(this, DicardResult, Initializing);
// but that's unnecessary of course.
Expand Down Expand Up @@ -3277,9 +3301,6 @@ template <class Emitter>
bool Compiler<Emitter>::visitInitializer(const Expr *E) {
assert(!classify(E->getType()));

if (E->containsErrors())
return this->emitError(E);

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

Expand Down Expand Up @@ -4364,11 +4385,6 @@ bool Compiler<Emitter>::visitReturnStmt(const ReturnStmt *RS) {
}

template <class Emitter> bool Compiler<Emitter>::visitIfStmt(const IfStmt *IS) {
if (IS->isNonNegatedConsteval())
return visitStmt(IS->getThen());
if (IS->isNegatedConsteval())
return IS->getElse() ? visitStmt(IS->getElse()) : true;

if (auto *CondInit = IS->getInit())
if (!visitStmt(CondInit))
return false;
Expand All @@ -4377,8 +4393,19 @@ template <class Emitter> bool Compiler<Emitter>::visitIfStmt(const IfStmt *IS) {
if (!visitDeclStmt(CondDecl))
return false;

if (!this->visitBool(IS->getCond()))
return false;
// Compile condition.
if (IS->isNonNegatedConsteval()) {
if (!this->emitIsConstantContext(IS))
return false;
} else if (IS->isNegatedConsteval()) {
if (!this->emitIsConstantContext(IS))
return false;
if (!this->emitInv(IS))
return false;
} else {
if (!this->visitBool(IS->getCond()))
return false;
}

if (const Stmt *Else = IS->getElse()) {
LabelTy LabelElse = this->getLabel();
Expand Down
23 changes: 10 additions & 13 deletions clang/lib/AST/ByteCode/Descriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,9 @@ static void dtorTy(Block *, std::byte *Ptr, const Descriptor *) {
}

template <typename T>
static void moveTy(Block *, const std::byte *Src, std::byte *Dst,
static void moveTy(Block *, std::byte *Src, std::byte *Dst,
const Descriptor *) {
// FIXME: Get rid of the const_cast.
auto *SrcPtr = reinterpret_cast<T *>(const_cast<std::byte *>(Src));
auto *SrcPtr = reinterpret_cast<T *>(Src);
auto *DstPtr = reinterpret_cast<T *>(Dst);
new (DstPtr) T(std::move(*SrcPtr));
}
Expand Down Expand Up @@ -63,11 +62,9 @@ static void dtorArrayTy(Block *, std::byte *Ptr, const Descriptor *D) {
}

template <typename T>
static void moveArrayTy(Block *, const std::byte *Src, std::byte *Dst,
static void moveArrayTy(Block *, std::byte *Src, std::byte *Dst,
const Descriptor *D) {
// FIXME: Get rid of the const_cast.
InitMapPtr &SrcIMP =
*reinterpret_cast<InitMapPtr *>(const_cast<std::byte *>(Src));
InitMapPtr &SrcIMP = *reinterpret_cast<InitMapPtr *>(Src);
if (SrcIMP) {
// We only ever invoke the moveFunc when moving block contents to a
// DeadBlock. DeadBlocks don't need InitMaps, so we destroy them here.
Expand All @@ -76,7 +73,7 @@ static void moveArrayTy(Block *, const std::byte *Src, std::byte *Dst,
Src += sizeof(InitMapPtr);
Dst += sizeof(InitMapPtr);
for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
auto *SrcPtr = &reinterpret_cast<T *>(const_cast<std::byte *>(Src))[I];
auto *SrcPtr = &reinterpret_cast<T *>(Src)[I];
auto *DstPtr = &reinterpret_cast<T *>(Dst)[I];
new (DstPtr) T(std::move(*SrcPtr));
}
Expand Down Expand Up @@ -126,19 +123,19 @@ static void dtorArrayDesc(Block *B, std::byte *Ptr, const Descriptor *D) {
}
}

static void moveArrayDesc(Block *B, const std::byte *Src, std::byte *Dst,
static void moveArrayDesc(Block *B, std::byte *Src, std::byte *Dst,
const Descriptor *D) {
const unsigned NumElems = D->getNumElems();
const unsigned ElemSize =
D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);

unsigned ElemOffset = 0;
for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {
const auto *SrcPtr = Src + ElemOffset;
auto *SrcPtr = Src + ElemOffset;
auto *DstPtr = Dst + ElemOffset;

const auto *SrcDesc = reinterpret_cast<const InlineDescriptor *>(SrcPtr);
const auto *SrcElemLoc = reinterpret_cast<const std::byte *>(SrcDesc + 1);
auto *SrcDesc = reinterpret_cast<InlineDescriptor *>(SrcPtr);
auto *SrcElemLoc = reinterpret_cast<std::byte *>(SrcDesc + 1);
auto *DstDesc = reinterpret_cast<InlineDescriptor *>(DstPtr);
auto *DstElemLoc = reinterpret_cast<std::byte *>(DstDesc + 1);

Expand Down Expand Up @@ -233,7 +230,7 @@ static void dtorRecord(Block *B, std::byte *Ptr, const Descriptor *D) {
destroyBase(B, Ptr, F.Desc, F.Offset);
}

static void moveRecord(Block *B, const std::byte *Src, std::byte *Dst,
static void moveRecord(Block *B, std::byte *Src, std::byte *Dst,
const Descriptor *D) {
assert(D);
assert(D->ElemRecord);
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/ByteCode/Descriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ using BlockDtorFn = void (*)(Block *Storage, std::byte *FieldPtr,
/// blocks are persisted: the move function copies all inline descriptors and
/// non-trivial fields, as existing pointers might need to reference those
/// descriptors. Data is not copied since it cannot be legally read.
using BlockMoveFn = void (*)(Block *Storage, const std::byte *SrcFieldPtr,
using BlockMoveFn = void (*)(Block *Storage, std::byte *SrcFieldPtr,
std::byte *DstFieldPtr,
const Descriptor *FieldDesc);

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/ByteCode/EvalEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ bool EvalEmitter::emitRetValue(const SourceInfo &Info) {
return false;

if (std::optional<APValue> APV =
Ptr.toRValue(S.getCtx(), EvalResult.getSourceType())) {
Ptr.toRValue(S.getASTContext(), EvalResult.getSourceType())) {
EvalResult.setValue(*APV);
return true;
}
Expand Down
43 changes: 43 additions & 0 deletions clang/lib/AST/ByteCode/FunctionPointer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//===----------------------- FunctionPointer.cpp ----------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "FunctionPointer.h"

namespace clang {
namespace interp {

APValue FunctionPointer::toAPValue(const ASTContext &) const {
if (!Func)
return APValue(static_cast<Expr *>(nullptr), CharUnits::Zero(), {},
/*OnePastTheEnd=*/false, /*IsNull=*/true);

if (!Valid)
return APValue(static_cast<Expr *>(nullptr),
CharUnits::fromQuantity(getIntegerRepresentation()), {},
/*OnePastTheEnd=*/false, /*IsNull=*/false);

if (Func->getDecl())
return APValue(Func->getDecl(), CharUnits::fromQuantity(Offset), {},
/*OnePastTheEnd=*/false, /*IsNull=*/false);
return APValue(Func->getExpr(), CharUnits::fromQuantity(Offset), {},
/*OnePastTheEnd=*/false, /*IsNull=*/false);
}

void FunctionPointer::print(llvm::raw_ostream &OS) const {
OS << "FnPtr(";
if (Func && Valid)
OS << Func->getName();
else if (Func)
OS << reinterpret_cast<uintptr_t>(Func);
else
OS << "nullptr";
OS << ") + " << Offset;
}

} // namespace interp
} // namespace clang
41 changes: 10 additions & 31 deletions clang/lib/AST/ByteCode/FunctionPointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,29 @@

#include "Function.h"
#include "Primitives.h"
#include "clang/AST/APValue.h"

namespace clang {
class ASTContext;
class APValue;
namespace interp {

class FunctionPointer final {
private:
const Function *Func;
uint64_t Offset;
bool Valid;

public:
FunctionPointer() = default;
FunctionPointer(const Function *Func) : Func(Func), Valid(true) {}
FunctionPointer(const Function *Func, uint64_t Offset = 0)
: Func(Func), Offset(Offset), Valid(true) {}

FunctionPointer(uintptr_t IntVal, const Descriptor *Desc = nullptr)
: Func(reinterpret_cast<const Function *>(IntVal)), Valid(false) {}
: Func(reinterpret_cast<const Function *>(IntVal)), Offset(0),
Valid(false) {}

const Function *getFunction() const { return Func; }
uint64_t getOffset() const { return Offset; }
bool isZero() const { return !Func; }
bool isValid() const { return Valid; }
bool isWeak() const {
Expand All @@ -39,33 +43,8 @@ class FunctionPointer final {
return Func->getDecl()->isWeak();
}

APValue toAPValue(const ASTContext &) const {
if (!Func)
return APValue(static_cast<Expr *>(nullptr), CharUnits::Zero(), {},
/*OnePastTheEnd=*/false, /*IsNull=*/true);

if (!Valid)
return APValue(static_cast<Expr *>(nullptr),
CharUnits::fromQuantity(getIntegerRepresentation()), {},
/*OnePastTheEnd=*/false, /*IsNull=*/false);

if (Func->getDecl())
return APValue(Func->getDecl(), CharUnits::Zero(), {},
/*OnePastTheEnd=*/false, /*IsNull=*/false);
return APValue(Func->getExpr(), CharUnits::Zero(), {},
/*OnePastTheEnd=*/false, /*IsNull=*/false);
}

void print(llvm::raw_ostream &OS) const {
OS << "FnPtr(";
if (Func && Valid)
OS << Func->getName();
else if (Func)
OS << reinterpret_cast<uintptr_t>(Func);
else
OS << "nullptr";
OS << ")";
}
APValue toAPValue(const ASTContext &) const;
void print(llvm::raw_ostream &OS) const;

std::string toDiagnosticString(const ASTContext &Ctx) const {
if (!Func)
Expand All @@ -79,7 +58,7 @@ class FunctionPointer final {
}

ComparisonCategoryResult compare(const FunctionPointer &RHS) const {
if (Func == RHS.Func)
if (Func == RHS.Func && Offset == RHS.Offset)
return ComparisonCategoryResult::Equal;
return ComparisonCategoryResult::Unordered;
}
Expand Down
14 changes: 11 additions & 3 deletions clang/lib/AST/ByteCode/IntegralAP.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,16 +136,24 @@ template <bool Signed> class IntegralAP final {
APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); }

bool isZero() const { return V.isZero(); }
bool isPositive() const { return V.isNonNegative(); }
bool isNegative() const { return !V.isNonNegative(); }
bool isPositive() const {
if constexpr (Signed)
return V.isNonNegative();
return true;
}
bool isNegative() const {
if constexpr (Signed)
return !V.isNonNegative();
return false;
}
bool isMin() const { return V.isMinValue(); }
bool isMax() const { return V.isMaxValue(); }
static constexpr bool isSigned() { return Signed; }
bool isMinusOne() const { return Signed && V == -1; }

unsigned countLeadingZeros() const { return V.countl_zero(); }

void print(llvm::raw_ostream &OS) const { OS << V; }
void print(llvm::raw_ostream &OS) const { V.print(OS, Signed);}
std::string toDiagnosticString(const ASTContext &Ctx) const {
std::string NameStr;
llvm::raw_string_ostream OS(NameStr);
Expand Down
10 changes: 5 additions & 5 deletions clang/lib/AST/ByteCode/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
auto IsConstType = [&S](const VarDecl *VD) -> bool {
QualType T = VD->getType();

if (T.isConstant(S.getCtx()))
if (T.isConstant(S.getASTContext()))
return true;

if (S.getLangOpts().CPlusPlus && !S.getLangOpts().CPlusPlus11)
Expand Down Expand Up @@ -523,9 +523,9 @@ bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
assert(S.getLangOpts().CPlusPlus);
const auto *VD = cast<VarDecl>(Ptr.getDeclDesc()->asValueDecl());
if ((!VD->hasConstantInitialization() &&
VD->mightBeUsableInConstantExpressions(S.getCtx())) ||
VD->mightBeUsableInConstantExpressions(S.getASTContext())) ||
(S.getLangOpts().OpenCL && !S.getLangOpts().CPlusPlus11 &&
!VD->hasICEInitializer(S.getCtx()))) {
!VD->hasICEInitializer(S.getASTContext()))) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
S.Note(VD->getLocation(), diag::note_declared_at);
Expand Down Expand Up @@ -797,7 +797,7 @@ bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, bool NewWasArray,
// but we want to get the array size right.
if (D->isArray()) {
QualType ElemQT = D->getType()->getPointeeType();
TypeToDiagnose = S.getCtx().getConstantArrayType(
TypeToDiagnose = S.getASTContext().getConstantArrayType(
ElemQT, APInt(64, static_cast<uint64_t>(D->getNumElems()), false),
nullptr, ArraySizeModifier::Normal, 0);
} else
Expand All @@ -819,7 +819,7 @@ bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source,
// Whatever this is, we didn't heap allocate it.
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_delete_not_heap_alloc)
<< Ptr.toDiagnosticString(S.getCtx());
<< Ptr.toDiagnosticString(S.getASTContext());

if (Ptr.isTemporary())
S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
Expand Down
100 changes: 68 additions & 32 deletions clang/lib/AST/ByteCode/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ using APSInt = llvm::APSInt;
/// Convert a value to an APValue.
template <typename T>
bool ReturnValue(const InterpState &S, const T &V, APValue &R) {
R = V.toAPValue(S.getCtx());
R = V.toAPValue(S.getASTContext());
return true;
}

Expand Down Expand Up @@ -231,12 +231,12 @@ bool CheckArraySize(InterpState &S, CodePtr OpPC, SizeT *NumElements,
// constructing the array, we catch this here.
SizeT MaxElements = SizeT::from(Descriptor::MaxArrayElemBytes / ElemSize);
if (NumElements->toAPSInt().getActiveBits() >
ConstantArrayType::getMaxSizeBits(S.getCtx()) ||
ConstantArrayType::getMaxSizeBits(S.getASTContext()) ||
*NumElements > MaxElements) {
if (!IsNoThrow) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_new_too_large)
<< NumElements->toDiagnosticString(S.getCtx());
<< NumElements->toDiagnosticString(S.getASTContext());
}
return false;
}
Expand Down Expand Up @@ -911,8 +911,8 @@ inline bool CmpHelper<FunctionPointer>(InterpState &S, CodePtr OpPC,

const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
<< LHS.toDiagnosticString(S.getCtx())
<< RHS.toDiagnosticString(S.getCtx());
<< LHS.toDiagnosticString(S.getASTContext())
<< RHS.toDiagnosticString(S.getASTContext());
return false;
}

Expand All @@ -927,7 +927,7 @@ inline bool CmpHelperEQ<FunctionPointer>(InterpState &S, CodePtr OpPC,
if (FP.isWeak()) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
<< FP.toDiagnosticString(S.getCtx());
<< FP.toDiagnosticString(S.getASTContext());
return false;
}
}
Expand All @@ -945,8 +945,8 @@ inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
if (!Pointer::hasSameBase(LHS, RHS)) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
<< LHS.toDiagnosticString(S.getCtx())
<< RHS.toDiagnosticString(S.getCtx());
<< LHS.toDiagnosticString(S.getASTContext())
<< RHS.toDiagnosticString(S.getASTContext());
return false;
} else {
unsigned VL = LHS.getByteOffset();
Expand Down Expand Up @@ -974,7 +974,7 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
if (P.isWeak()) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
<< P.toDiagnosticString(S.getCtx());
<< P.toDiagnosticString(S.getASTContext());
return false;
}
}
Expand All @@ -984,13 +984,13 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
RHS.getOffset() == 0) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
<< LHS.toDiagnosticString(S.getCtx());
<< LHS.toDiagnosticString(S.getASTContext());
return false;
} else if (RHS.isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() &&
LHS.getOffset() == 0) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
<< RHS.toDiagnosticString(S.getCtx());
<< RHS.toDiagnosticString(S.getASTContext());
return false;
}

Expand Down Expand Up @@ -1073,8 +1073,8 @@ bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo) {
// This should only happen with pointers.
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
<< LHS.toDiagnosticString(S.getCtx())
<< RHS.toDiagnosticString(S.getCtx());
<< LHS.toDiagnosticString(S.getASTContext())
<< RHS.toDiagnosticString(S.getASTContext());
return false;
}

Expand Down Expand Up @@ -1342,7 +1342,7 @@ bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I,
const Pointer &Ptr = S.P.getGlobal(I);

const T Value = S.Stk.peek<T>();
APValue APV = Value.toAPValue(S.getCtx());
APValue APV = Value.toAPValue(S.getASTContext());
APValue *Cached = Temp->getOrCreateValue(true);
*Cached = APV;

Expand All @@ -1369,7 +1369,7 @@ inline bool InitGlobalTempComp(InterpState &S, CodePtr OpPC,
std::make_pair(P.getDeclDesc()->asExpr(), Temp));

if (std::optional<APValue> APV =
P.toRValue(S.getCtx(), Temp->getTemporaryExpr()->getType())) {
P.toRValue(S.getASTContext(), Temp->getTemporaryExpr()->getType())) {
*Cached = *APV;
return true;
}
Expand Down Expand Up @@ -1404,7 +1404,8 @@ bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F,
return false;
const Pointer &Field = This.atField(FieldOffset);
const auto &Value = S.Stk.pop<T>();
Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
Field.deref<T>() =
Value.truncate(F->Decl->getBitWidthValue(S.getASTContext()));
Field.initialize();
return true;
}
Expand All @@ -1427,7 +1428,8 @@ bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
assert(F->isBitField());
const T &Value = S.Stk.pop<T>();
const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset);
Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
Field.deref<T>() =
Value.truncate(F->Decl->getBitWidthValue(S.getASTContext()));
Field.activate();
Field.initialize();
return true;
Expand Down Expand Up @@ -1477,7 +1479,7 @@ inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
return false;

if (Ptr.isIntegralPointer()) {
S.Stk.push<Pointer>(Ptr.asIntPointer().atOffset(S.getCtx(), Off));
S.Stk.push<Pointer>(Ptr.asIntPointer().atOffset(S.getASTContext(), Off));
return true;
}

Expand Down Expand Up @@ -1505,7 +1507,7 @@ inline bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
return false;

if (Ptr.isIntegralPointer()) {
S.Stk.push<Pointer>(Ptr.asIntPointer().atOffset(S.getCtx(), Off));
S.Stk.push<Pointer>(Ptr.asIntPointer().atOffset(S.getASTContext(), Off));
return true;
}

Expand Down Expand Up @@ -1721,7 +1723,7 @@ bool StoreBitField(InterpState &S, CodePtr OpPC) {
if (Ptr.canBeInitialized())
Ptr.initialize();
if (const auto *FD = Ptr.getField())
Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getASTContext()));
else
Ptr.deref<T>() = Value;
return true;
Expand All @@ -1736,7 +1738,7 @@ bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {
if (Ptr.canBeInitialized())
Ptr.initialize();
if (const auto *FD = Ptr.getField())
Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getASTContext()));
else
Ptr.deref<T>() = Value;
return true;
Expand Down Expand Up @@ -1857,8 +1859,23 @@ bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
else
S.Stk.push<Pointer>(V - O, Ptr.asIntPointer().Desc);
return true;
} else if (Ptr.isFunctionPointer()) {
uint64_t O = static_cast<uint64_t>(Offset);
uint64_t N;
if constexpr (Op == ArithOp::Add)
N = Ptr.getByteOffset() + O;
else
N = Ptr.getByteOffset() - O;

if (N > 1)
S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
<< N << /*non-array*/ true << 0;
S.Stk.push<Pointer>(Ptr.asFunctionPointer().getFunction(), N);
return true;
}

assert(Ptr.isBlockPointer());

uint64_t MaxIndex = static_cast<uint64_t>(Ptr.getNumElems());
uint64_t Index;
if (Ptr.isOnePastEnd())
Expand Down Expand Up @@ -1999,7 +2016,7 @@ inline bool SubPtr(InterpState &S, CodePtr OpPC) {
while (auto *AT = dyn_cast<ArrayType>(PtrT))
PtrT = AT->getElementType();

QualType ArrayTy = S.getCtx().getConstantArrayType(
QualType ArrayTy = S.getASTContext().getConstantArrayType(
PtrT, APInt::getZero(1), nullptr, ArraySizeModifier::Normal, 0);
S.FFDiag(S.Current->getSource(OpPC),
diag::note_constexpr_pointer_subtraction_zero_size)
Expand All @@ -2024,10 +2041,15 @@ inline bool SubPtr(InterpState &S, CodePtr OpPC) {
return true;
}

T A = LHS.isElementPastEnd() ? T::from(LHS.getNumElems())
: T::from(LHS.getIndex());
T B = RHS.isElementPastEnd() ? T::from(RHS.getNumElems())
: T::from(RHS.getIndex());
T A = LHS.isBlockPointer()
? (LHS.isElementPastEnd() ? T::from(LHS.getNumElems())
: T::from(LHS.getIndex()))
: T::from(LHS.getIntegerRepresentation());
T B = RHS.isBlockPointer()
? (RHS.isElementPastEnd() ? T::from(RHS.getNumElems())
: T::from(RHS.getIndex()))
: T::from(RHS.getIntegerRepresentation());

return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);
}

Expand Down Expand Up @@ -2588,9 +2610,11 @@ inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
// 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 (S.Current->getFunction() &&
S.Current->getFunction()->isLambdaStaticInvoker() &&
Func->isLambdaCallOperator()) {
assert(ThisPtr.isZero());
} else {
if (!CheckInvoke(S, OpPC, ThisPtr))
return false;
}
Expand Down Expand Up @@ -2905,8 +2929,15 @@ inline bool DecayPtr(InterpState &S, CodePtr OpPC) {

if constexpr (std::is_same_v<FromT, FunctionPointer> &&
std::is_same_v<ToT, Pointer>) {
S.Stk.push<Pointer>(OldPtr.getFunction());
S.Stk.push<Pointer>(OldPtr.getFunction(), OldPtr.getOffset());
return true;
} else if constexpr (std::is_same_v<FromT, Pointer> &&
std::is_same_v<ToT, FunctionPointer>) {
if (OldPtr.isFunctionPointer()) {
S.Stk.push<FunctionPointer>(OldPtr.asFunctionPointer().getFunction(),
OldPtr.getByteOffset());
return true;
}
}

S.Stk.push<ToT>(ToT(OldPtr.getIntegerRepresentation(), nullptr));
Expand All @@ -2924,7 +2955,7 @@ inline bool CheckDecl(InterpState &S, CodePtr OpPC, const VarDecl *VD) {
if (VD == S.EvaluatingDecl)
return true;

if (!VD->isUsableInConstantExpressions(S.getCtx())) {
if (!VD->isUsableInConstantExpressions(S.getASTContext())) {
S.CCEDiag(VD->getLocation(), diag::note_constexpr_static_local)
<< (VD->getTSCSpec() == TSCS_unspecified ? 0 : 1) << VD;
return false;
Expand Down Expand Up @@ -3018,7 +3049,7 @@ static inline bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm) {
if (!Ptr.isRoot() || Ptr.isOnePastEnd() || Ptr.isArrayElement()) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_delete_subobject)
<< Ptr.toDiagnosticString(S.getCtx()) << Ptr.isOnePastEnd();
<< Ptr.toDiagnosticString(S.getASTContext()) << Ptr.isOnePastEnd();
return false;
}

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

static inline bool IsConstantContext(InterpState &S, CodePtr OpPC) {
S.Stk.push<Boolean>(Boolean::from(S.inConstantContext()));
return true;
}

inline bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T) {
assert(T);
assert(!S.getLangOpts().CPlusPlus23);
Expand Down
41 changes: 21 additions & 20 deletions clang/lib/AST/ByteCode/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ static T getParam(const InterpFrame *Frame, unsigned Index) {
}

PrimType getIntPrimType(const InterpState &S) {
const TargetInfo &TI = S.getCtx().getTargetInfo();
const TargetInfo &TI = S.getASTContext().getTargetInfo();
unsigned IntWidth = TI.getIntWidth();

if (IntWidth == 32)
Expand All @@ -49,7 +49,7 @@ PrimType getIntPrimType(const InterpState &S) {
}

PrimType getLongPrimType(const InterpState &S) {
const TargetInfo &TI = S.getCtx().getTargetInfo();
const TargetInfo &TI = S.getASTContext().getTargetInfo();
unsigned LongWidth = TI.getLongWidth();

if (LongWidth == 64)
Expand Down Expand Up @@ -272,10 +272,10 @@ static bool interp__builtin_nan(InterpState &S, CodePtr OpPC,
return false;

const llvm::fltSemantics &TargetSemantics =
S.getCtx().getFloatTypeSemantics(F->getDecl()->getReturnType());
S.getASTContext().getFloatTypeSemantics(F->getDecl()->getReturnType());

Floating Result;
if (S.getCtx().getTargetInfo().isNan2008()) {
if (S.getASTContext().getTargetInfo().isNan2008()) {
if (Signaling)
Result = Floating(
llvm::APFloat::getSNaN(TargetSemantics, /*Negative=*/false, &Fill));
Expand Down Expand Up @@ -303,7 +303,7 @@ static bool interp__builtin_nan(InterpState &S, CodePtr OpPC,
static bool interp__builtin_inf(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame, const Function *F) {
const llvm::fltSemantics &TargetSemantics =
S.getCtx().getFloatTypeSemantics(F->getDecl()->getReturnType());
S.getASTContext().getFloatTypeSemantics(F->getDecl()->getReturnType());

S.Stk.push<Floating>(Floating::getInf(TargetSemantics));
return true;
Expand Down Expand Up @@ -689,8 +689,8 @@ static bool interp__builtin_eh_return_data_regno(InterpState &S, CodePtr OpPC,
PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
APSInt Arg = peekToAPSInt(S.Stk, ArgT);

int Result =
S.getCtx().getTargetInfo().getEHDataRegisterNumber(Arg.getZExtValue());
int Result = S.getASTContext().getTargetInfo().getEHDataRegisterNumber(
Arg.getZExtValue());
pushInteger(S, Result, Call->getType());
return true;
}
Expand Down Expand Up @@ -734,7 +734,7 @@ static bool interp__builtin_overflowop(InterpState &S, CodePtr OpPC,
ResultType->isSignedIntegerOrEnumerationType();
uint64_t LHSSize = LHS.getBitWidth();
uint64_t RHSSize = RHS.getBitWidth();
uint64_t ResultSize = S.getCtx().getTypeSize(ResultType);
uint64_t ResultSize = S.getASTContext().getTypeSize(ResultType);
uint64_t MaxBits = std::max(std::max(LHSSize, RHSSize), ResultSize);

// Add an additional bit if the signedness isn't uniformly agreed to. We
Expand Down Expand Up @@ -794,7 +794,7 @@ static bool interp__builtin_overflowop(InterpState &S, CodePtr OpPC,
// since it will give us the behavior of a TruncOrSelf in the case where
// its parameter <= its size. We previously set Result to be at least the
// type-size of the result, so getTypeSize(ResultType) <= Resu
APSInt Temp = Result.extOrTrunc(S.getCtx().getTypeSize(ResultType));
APSInt Temp = Result.extOrTrunc(S.getASTContext().getTypeSize(ResultType));
Temp.setIsSigned(ResultType->isSignedIntegerOrEnumerationType());

if (!APSInt::isSameValue(Temp, Result))
Expand Down Expand Up @@ -974,8 +974,8 @@ static bool interp__builtin_atomic_lock_free(InterpState &S, CodePtr OpPC,
if (Size.isPowerOfTwo()) {
// Check against inlining width.
unsigned InlineWidthBits =
S.getCtx().getTargetInfo().getMaxAtomicInlineWidth();
if (Size <= S.getCtx().toCharUnitsFromBits(InlineWidthBits)) {
S.getASTContext().getTargetInfo().getMaxAtomicInlineWidth();
if (Size <= S.getASTContext().toCharUnitsFromBits(InlineWidthBits)) {

// OK, we will inline appropriately-aligned operations of this size,
// and _Atomic(T) is appropriately-aligned.
Expand Down Expand Up @@ -1007,7 +1007,7 @@ static bool interp__builtin_atomic_lock_free(InterpState &S, CodePtr OpPC,
if (auto PtrTy = PtrArg->getType()->getAs<PointerType>()) {
QualType PointeeType = PtrTy->getPointeeType();
if (!PointeeType->isIncompleteType() &&
S.getCtx().getTypeAlignInChars(PointeeType) >= Size) {
S.getASTContext().getTypeAlignInChars(PointeeType) >= Size) {
// OK, we will inline operations on this object.
return returnBool(true);
}
Expand Down Expand Up @@ -1059,7 +1059,7 @@ static bool interp__builtin_is_aligned_up_down(InterpState &S, CodePtr OpPC,
S.FFDiag(Call, diag::note_constexpr_invalid_alignment) << Alignment;
return false;
}
unsigned SrcWidth = S.getCtx().getIntWidth(Call->getArg(0)->getType());
unsigned SrcWidth = S.getASTContext().getIntWidth(Call->getArg(0)->getType());
APSInt MaxValue(APInt::getOneBitSet(SrcWidth, SrcWidth - 1));
if (APSInt::compareValues(Alignment, MaxValue) > 0) {
S.FFDiag(Call, diag::note_constexpr_alignment_too_big)
Expand Down Expand Up @@ -1094,7 +1094,7 @@ static bool interp__builtin_is_aligned_up_down(InterpState &S, CodePtr OpPC,
unsigned PtrOffset = Ptr.getByteOffset();
PtrOffset = Ptr.getIndex();
CharUnits BaseAlignment =
S.getCtx().getDeclAlign(Ptr.getDeclDesc()->asValueDecl());
S.getASTContext().getDeclAlign(Ptr.getDeclDesc()->asValueDecl());
CharUnits PtrAlign =
BaseAlignment.alignmentAtOffset(CharUnits::fromQuantity(PtrOffset));

Expand Down Expand Up @@ -1157,7 +1157,7 @@ static bool interp__builtin_os_log_format_buffer_size(InterpState &S,
const Function *Func,
const CallExpr *Call) {
analyze_os_log::OSLogBufferLayout Layout;
analyze_os_log::computeOSLogBufferLayout(S.getCtx(), Call, Layout);
analyze_os_log::computeOSLogBufferLayout(S.getASTContext(), Call, Layout);
pushInteger(S, Layout.size().getQuantity(), Call->getType());
return true;
}
Expand Down Expand Up @@ -1624,22 +1624,23 @@ bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
const RecordDecl *RD = RT->getDecl();
if (RD->isInvalidDecl())
return false;
const ASTRecordLayout &RL = S.getCtx().getASTRecordLayout(RD);
const ASTRecordLayout &RL = S.getASTContext().getASTRecordLayout(RD);
unsigned FieldIndex = MemberDecl->getFieldIndex();
assert(FieldIndex < RL.getFieldCount() && "offsetof field in wrong type");
Result += S.getCtx().toCharUnitsFromBits(RL.getFieldOffset(FieldIndex));
Result +=
S.getASTContext().toCharUnitsFromBits(RL.getFieldOffset(FieldIndex));
CurrentType = MemberDecl->getType().getNonReferenceType();
break;
}
case OffsetOfNode::Array: {
// When generating bytecode, we put all the index expressions as Sint64 on
// the stack.
int64_t Index = ArrayIndices[ArrayIndex];
const ArrayType *AT = S.getCtx().getAsArrayType(CurrentType);
const ArrayType *AT = S.getASTContext().getAsArrayType(CurrentType);
if (!AT)
return false;
CurrentType = AT->getElementType();
CharUnits ElementSize = S.getCtx().getTypeSizeInChars(CurrentType);
CharUnits ElementSize = S.getASTContext().getTypeSizeInChars(CurrentType);
Result += Index * ElementSize;
++ArrayIndex;
break;
Expand All @@ -1656,7 +1657,7 @@ bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
const RecordDecl *RD = RT->getDecl();
if (RD->isInvalidDecl())
return false;
const ASTRecordLayout &RL = S.getCtx().getASTRecordLayout(RD);
const ASTRecordLayout &RL = S.getASTContext().getASTRecordLayout(RD);

// Find the base class itself.
CurrentType = BaseSpec->getType();
Expand Down
14 changes: 7 additions & 7 deletions clang/lib/AST/ByteCode/InterpFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ void InterpFrame::describe(llvm::raw_ostream &OS) const {
if (const auto *MCE = dyn_cast_if_present<CXXMemberCallExpr>(CallExpr)) {
const Expr *Object = MCE->getImplicitObjectArgument();
Object->printPretty(OS, /*Helper=*/nullptr,
S.getCtx().getPrintingPolicy(),
S.getASTContext().getPrintingPolicy(),
/*Indentation=*/0);
if (Object->getType()->isPointerType())
OS << "->";
Expand All @@ -188,18 +188,18 @@ void InterpFrame::describe(llvm::raw_ostream &OS) const {
} else if (const auto *OCE =
dyn_cast_if_present<CXXOperatorCallExpr>(CallExpr)) {
OCE->getArg(0)->printPretty(OS, /*Helper=*/nullptr,
S.getCtx().getPrintingPolicy(),
S.getASTContext().getPrintingPolicy(),
/*Indentation=*/0);
OS << ".";
} else if (const auto *M = dyn_cast<CXXMethodDecl>(F)) {
print(OS, This, S.getCtx(),
S.getCtx().getLValueReferenceType(
S.getCtx().getRecordType(M->getParent())));
print(OS, This, S.getASTContext(),
S.getASTContext().getLValueReferenceType(
S.getASTContext().getRecordType(M->getParent())));
OS << ".";
}
}

F->getNameForDiagnostic(OS, S.getCtx().getPrintingPolicy(),
F->getNameForDiagnostic(OS, S.getASTContext().getPrintingPolicy(),
/*Qualified=*/false);
OS << '(';
unsigned Off = 0;
Expand All @@ -212,7 +212,7 @@ void InterpFrame::describe(llvm::raw_ostream &OS) const {

PrimType PrimTy = S.Ctx.classify(Ty).value_or(PT_Ptr);

TYPE_SWITCH(PrimTy, print(OS, stackRef<T>(Off), S.getCtx(), Ty));
TYPE_SWITCH(PrimTy, print(OS, stackRef<T>(Off), S.getASTContext(), Ty));
Off += align(primSize(PrimTy));
if (I + 1 != N)
OS << ", ";
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/ByteCode/InterpState.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class InterpState final : public State, public SourceMapper {
Expr::EvalStatus &getEvalStatus() const override {
return Parent.getEvalStatus();
}
ASTContext &getCtx() const override { return Parent.getCtx(); }
ASTContext &getASTContext() const override { return Parent.getASTContext(); }

// Forward status checks and updates to the walker.
bool checkingForUndefinedBehavior() const override {
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/ByteCode/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -780,3 +780,5 @@ def AllocCN : Opcode {
def Free : Opcode {
let Args = [ArgBool];
}

def IsConstantContext: Opcode;
6 changes: 4 additions & 2 deletions clang/lib/AST/ByteCode/Pointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ class Pointer {
if (isIntegralPointer())
return asIntPointer().Value + (Offset * elemSize());
if (isFunctionPointer())
return asFunctionPointer().getIntegerRepresentation();
return asFunctionPointer().getIntegerRepresentation() + Offset;
return reinterpret_cast<uint64_t>(asBlockPointer().Pointee) + Offset;
}

Expand Down Expand Up @@ -551,7 +551,7 @@ class Pointer {
}

/// Returns the byte offset from the start.
unsigned getByteOffset() const {
uint64_t getByteOffset() const {
if (isIntegralPointer())
return asIntPointer().Value + Offset;
if (isOnePastEnd())
Expand Down Expand Up @@ -614,6 +614,8 @@ class Pointer {

/// Checks if the pointer is pointing to a zero-size array.
bool isZeroSizeArray() const {
if (isFunctionPointer())
return false;
if (const auto *Desc = getFieldDesc())
return Desc->isZeroSizeArray();
return false;
Expand Down
11 changes: 7 additions & 4 deletions clang/lib/AST/ByteCode/State.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,12 @@ void State::addNotes(ArrayRef<PartialDiagnosticAt> Diags) {
}

DiagnosticBuilder State::report(SourceLocation Loc, diag::kind DiagId) {
return getCtx().getDiagnostics().Report(Loc, DiagId);
return getASTContext().getDiagnostics().Report(Loc, DiagId);
}

/// Add a diagnostic to the diagnostics list.
PartialDiagnostic &State::addDiag(SourceLocation Loc, diag::kind DiagId) {
PartialDiagnostic PD(DiagId, getCtx().getDiagAllocator());
PartialDiagnostic PD(DiagId, getASTContext().getDiagAllocator());
getEvalStatus().Diag->push_back(std::make_pair(Loc, PD));
return getEvalStatus().Diag->back().second;
}
Expand All @@ -93,7 +93,8 @@ OptionalDiagnostic State::diag(SourceLocation Loc, diag::kind DiagId,
}

unsigned CallStackNotes = getCallStackDepth() - 1;
unsigned Limit = getCtx().getDiagnostics().getConstexprBacktraceLimit();
unsigned Limit =
getASTContext().getDiagnostics().getConstexprBacktraceLimit();
if (Limit)
CallStackNotes = std::min(CallStackNotes, Limit + 1);
if (checkingPotentialConstantExpression())
Expand All @@ -113,7 +114,9 @@ OptionalDiagnostic State::diag(SourceLocation Loc, diag::kind DiagId,
return OptionalDiagnostic();
}

const LangOptions &State::getLangOpts() const { return getCtx().getLangOpts(); }
const LangOptions &State::getLangOpts() const {
return getASTContext().getLangOpts();
}

void State::addCallStack(unsigned Limit) {
// Determine which calls to skip, if any.
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/ByteCode/State.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class State {
virtual void setActiveDiagnostic(bool Flag) = 0;
virtual void setFoldFailureDiagnostic(bool Flag) = 0;
virtual Expr::EvalStatus &getEvalStatus() const = 0;
virtual ASTContext &getCtx() const = 0;
virtual ASTContext &getASTContext() const = 0;
virtual bool hasPriorDiagnostic() = 0;
virtual unsigned getCallStackDepth() = 0;

Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ add_clang_library(clangAST
ByteCode/EvalEmitter.cpp
ByteCode/Frame.cpp
ByteCode/Function.cpp
ByteCode/FunctionPointer.cpp
ByteCode/InterpBuiltin.cpp
ByteCode/Floating.cpp
ByteCode/EvaluationResult.cpp
Expand Down
14 changes: 11 additions & 3 deletions clang/lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2799,9 +2799,17 @@ bool VarDecl::isKnownToBeDefined() const {
}

bool VarDecl::isNoDestroy(const ASTContext &Ctx) const {
return hasGlobalStorage() && (hasAttr<NoDestroyAttr>() ||
(!Ctx.getLangOpts().RegisterStaticDestructors &&
!hasAttr<AlwaysDestroyAttr>()));
if (!hasGlobalStorage())
return false;
if (hasAttr<NoDestroyAttr>())
return true;
if (hasAttr<AlwaysDestroyAttr>())
return false;

using RSDKind = LangOptions::RegisterStaticDestructorsKind;
RSDKind K = Ctx.getLangOpts().getRegisterStaticDestructors();
return K == RSDKind::None ||
(K == RSDKind::ThreadLocal && getTLSKind() == TLS_None);
}

QualType::DestructionKind
Expand Down
27 changes: 21 additions & 6 deletions clang/lib/AST/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4806,6 +4806,26 @@ getOverflowPatternBinOp(const BinaryOperator *E) {
return {};
}

/// Compute and set the OverflowPatternExclusion bit based on whether the
/// BinaryOperator expression matches an overflow pattern being ignored by
/// -fsanitize-undefined-ignore-overflow-pattern=add-signed-overflow-test or
/// -fsanitize-undefined-ignore-overflow-pattern=add-unsigned-overflow-test
static void computeOverflowPatternExclusion(const ASTContext &Ctx,
const BinaryOperator *E) {
std::optional<BinaryOperator *> Result = getOverflowPatternBinOp(E);
if (!Result.has_value())
return;
QualType AdditionResultType = Result.value()->getType();

if ((AdditionResultType->isSignedIntegerType() &&
Ctx.getLangOpts().isOverflowPatternExcluded(
LangOptions::OverflowPatternExclusionKind::AddSignedOverflowTest)) ||
(AdditionResultType->isUnsignedIntegerType() &&
Ctx.getLangOpts().isOverflowPatternExcluded(
LangOptions::OverflowPatternExclusionKind::AddUnsignedOverflowTest)))
Result.value()->setExcludedOverflowPattern(true);
}

BinaryOperator::BinaryOperator(const ASTContext &Ctx, Expr *lhs, Expr *rhs,
Opcode opc, QualType ResTy, ExprValueKind VK,
ExprObjectKind OK, SourceLocation opLoc,
Expand All @@ -4818,12 +4838,7 @@ BinaryOperator::BinaryOperator(const ASTContext &Ctx, Expr *lhs, Expr *rhs,
BinaryOperatorBits.ExcludedOverflowPattern = false;
SubExprs[LHS] = lhs;
SubExprs[RHS] = rhs;
if (Ctx.getLangOpts().isOverflowPatternExcluded(
LangOptions::OverflowPatternExclusionKind::AddOverflowTest)) {
std::optional<BinaryOperator *> Result = getOverflowPatternBinOp(this);
if (Result.has_value())
Result.value()->BinaryOperatorBits.ExcludedOverflowPattern = true;
}
computeOverflowPatternExclusion(Ctx, this);
BinaryOperatorBits.HasFPFeatures = FPFeatures.requiresTrailingStorage();
if (hasStoredFPFeatures())
setStoredFPFeatures(FPFeatures);
Expand Down
75 changes: 46 additions & 29 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1030,7 +1030,7 @@ namespace {
discardCleanups();
}

ASTContext &getCtx() const override { return Ctx; }
ASTContext &getASTContext() const override { return Ctx; }

void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value,
EvaluatingDeclKind EDK = EvaluatingDeclKind::Ctor) {
Expand Down Expand Up @@ -2327,9 +2327,9 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,

// In CUDA/HIP device compilation, only device side variables have
// constant addresses.
if (Info.getCtx().getLangOpts().CUDA &&
Info.getCtx().getLangOpts().CUDAIsDevice &&
Info.getCtx().CUDAConstantEvalCtx.NoWrongSidedVars) {
if (Info.getASTContext().getLangOpts().CUDA &&
Info.getASTContext().getLangOpts().CUDAIsDevice &&
Info.getASTContext().CUDAConstantEvalCtx.NoWrongSidedVars) {
if ((!Var->hasAttr<CUDADeviceAttr>() &&
!Var->hasAttr<CUDAConstantAttr>() &&
!Var->getType()->isCUDADeviceBuiltinSurfaceType() &&
Expand Down Expand Up @@ -5662,7 +5662,7 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
*Info.CurrentCall, hasSpecificAttr<MSConstexprAttr>(AS->getAttrs()) &&
isa<ReturnStmt>(SS));

auto LO = Info.getCtx().getLangOpts();
auto LO = Info.getASTContext().getLangOpts();
if (LO.CXXAssumptions && !LO.MSVCCompat) {
for (auto *Attr : AS->getAttrs()) {
auto *AA = dyn_cast<CXXAssumeAttr>(Attr);
Expand All @@ -5673,7 +5673,7 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
if (Assumption->isValueDependent())
return ESR_Failed;

if (Assumption->HasSideEffects(Info.getCtx()))
if (Assumption->HasSideEffects(Info.getASTContext()))
continue;

bool Value;
Expand Down Expand Up @@ -6691,7 +6691,9 @@ static bool HandleDestructionImpl(EvalInfo &Info, SourceRange CallRange,
if (Size && Size > Value.getArrayInitializedElts())
expandArray(Value, Value.getArraySize() - 1);

for (; Size != 0; --Size) {
// The size of the array might have been reduced by
// a placement new.
for (Size = Value.getArraySize(); Size != 0; --Size) {
APValue &Elem = Value.getArrayInitializedElt(Size - 1);
if (!HandleLValueArrayAdjustment(Info, &LocE, ElemLV, ElemT, -1) ||
!HandleDestructionImpl(Info, CallRange, ElemLV, Elem, ElemT))
Expand Down Expand Up @@ -10003,23 +10005,14 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
return false;

FunctionDecl *OperatorNew = E->getOperatorNew();
QualType AllocType = E->getAllocatedType();
QualType TargetType = AllocType;

bool IsNothrow = false;
bool IsPlacement = false;
if (OperatorNew->isReservedGlobalPlacementOperator() &&
Info.CurrentCall->isStdFunction() && !E->isArray()) {
// FIXME Support array placement new.
assert(E->getNumPlacementArgs() == 1);
if (!EvaluatePointer(E->getPlacementArg(0), Result, Info))
return false;
if (Result.Designator.Invalid)
return false;
IsPlacement = true;
} else if (!OperatorNew->isReplaceableGlobalAllocationFunction()) {
Info.FFDiag(E, diag::note_constexpr_new_non_replaceable)
<< isa<CXXMethodDecl>(OperatorNew) << OperatorNew;
return false;
} else if (E->getNumPlacementArgs()) {

if (E->getNumPlacementArgs() == 1 &&
E->getPlacementArg(0)->getType()->isNothrowT()) {
// The only new-placement list we support is of the form (std::nothrow).
//
// FIXME: There is no restriction on this, but it's not clear that any
Expand All @@ -10030,22 +10023,38 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
// (which should presumably be valid only if N is a multiple of
// alignof(int), and in any case can't be deallocated unless N is
// alignof(X) and X has new-extended alignment).
if (E->getNumPlacementArgs() != 1 ||
!E->getPlacementArg(0)->getType()->isNothrowT())
return Error(E, diag::note_constexpr_new_placement);

LValue Nothrow;
if (!EvaluateLValue(E->getPlacementArg(0), Nothrow, Info))
return false;
IsNothrow = true;
} else if (OperatorNew->isReservedGlobalPlacementOperator()) {
if (Info.CurrentCall->isStdFunction() || Info.getLangOpts().CPlusPlus26) {
if (!EvaluatePointer(E->getPlacementArg(0), Result, Info))
return false;
if (Result.Designator.Invalid)
return false;
TargetType = E->getPlacementArg(0)->getType();
IsPlacement = true;
} else {
Info.FFDiag(E, diag::note_constexpr_new_placement)
<< /*C++26 feature*/ 1 << E->getSourceRange();
return false;
}
} else if (E->getNumPlacementArgs()) {
Info.FFDiag(E, diag::note_constexpr_new_placement)
<< /*Unsupported*/ 0 << E->getSourceRange();
return false;
} else if (!OperatorNew->isReplaceableGlobalAllocationFunction()) {
Info.FFDiag(E, diag::note_constexpr_new_non_replaceable)
<< isa<CXXMethodDecl>(OperatorNew) << OperatorNew;
return false;
}

const Expr *Init = E->getInitializer();
const InitListExpr *ResizedArrayILE = nullptr;
const CXXConstructExpr *ResizedArrayCCE = nullptr;
bool ValueInit = false;

QualType AllocType = E->getAllocatedType();
if (std::optional<const Expr *> ArraySize = E->getArraySize()) {
const Expr *Stripped = *ArraySize;
for (; auto *ICE = dyn_cast<ImplicitCastExpr>(Stripped);
Expand Down Expand Up @@ -10139,9 +10148,17 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
bool found(APValue &Subobj, QualType SubobjType) {
// FIXME: Reject the cases where [basic.life]p8 would not permit the
// old name of the object to be used to name the new object.
if (!Info.Ctx.hasSameUnqualifiedType(SubobjType, AllocType)) {
Info.FFDiag(E, diag::note_constexpr_placement_new_wrong_type) <<
SubobjType << AllocType;
unsigned SubobjectSize = 1;
unsigned AllocSize = 1;
if (auto *CAT = dyn_cast<ConstantArrayType>(AllocType))
AllocSize = CAT->getZExtSize();
if (auto *CAT = dyn_cast<ConstantArrayType>(SubobjType))
SubobjectSize = CAT->getZExtSize();
if (SubobjectSize < AllocSize ||
!Info.Ctx.hasSimilarType(Info.Ctx.getBaseElementType(SubobjType),
Info.Ctx.getBaseElementType(AllocType))) {
Info.FFDiag(E, diag::note_constexpr_placement_new_wrong_type)
<< SubobjType << AllocType;
return false;
}
Value = &Subobj;
Expand Down
169 changes: 160 additions & 9 deletions clang/lib/AST/MicrosoftMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,8 @@ class MicrosoftCXXNameMangler {
void mangleSourceName(StringRef Name);
void mangleNestedName(GlobalDecl GD);

void mangleAutoReturnType(QualType T, QualifierMangleMode QMM);

private:
bool isStructorDecl(const NamedDecl *ND) const {
return ND == Structor || getStructor(ND) == Structor;
Expand Down Expand Up @@ -477,6 +479,11 @@ class MicrosoftCXXNameMangler {
SourceRange Range);
void mangleObjCKindOfType(const ObjCObjectType *T, Qualifiers Quals,
SourceRange Range);

void mangleAutoReturnType(const MemberPointerType *T, Qualifiers Quals);
void mangleAutoReturnType(const PointerType *T, Qualifiers Quals);
void mangleAutoReturnType(const LValueReferenceType *T, Qualifiers Quals);
void mangleAutoReturnType(const RValueReferenceType *T, Qualifiers Quals);
};
}

Expand Down Expand Up @@ -2494,6 +2501,57 @@ void MicrosoftCXXNameMangler::mangleAddressSpaceType(QualType T,
mangleArtificialTagType(TagTypeKind::Struct, ASMangling, {"__clang"});
}

void MicrosoftCXXNameMangler::mangleAutoReturnType(QualType T,
QualifierMangleMode QMM) {
assert(getASTContext().getLangOpts().isCompatibleWithMSVC(
LangOptions::MSVC2019) &&
"Cannot mangle MSVC 2017 auto return types!");

if (isa<AutoType>(T)) {
const auto *AT = T->getContainedAutoType();
Qualifiers Quals = T.getLocalQualifiers();

if (QMM == QMM_Result)
Out << '?';
if (QMM != QMM_Drop)
mangleQualifiers(Quals, false);
Out << (AT->isDecltypeAuto() ? "_T" : "_P");
return;
}

T = T.getDesugaredType(getASTContext());
Qualifiers Quals = T.getLocalQualifiers();

switch (QMM) {
case QMM_Drop:
case QMM_Result:
break;
case QMM_Mangle:
mangleQualifiers(Quals, false);
break;
default:
llvm_unreachable("QMM_Escape unexpected");
}

const Type *ty = T.getTypePtr();
switch (ty->getTypeClass()) {
case Type::MemberPointer:
mangleAutoReturnType(cast<MemberPointerType>(ty), Quals);
break;
case Type::Pointer:
mangleAutoReturnType(cast<PointerType>(ty), Quals);
break;
case Type::LValueReference:
mangleAutoReturnType(cast<LValueReferenceType>(ty), Quals);
break;
case Type::RValueReference:
mangleAutoReturnType(cast<RValueReferenceType>(ty), Quals);
break;
default:
llvm_unreachable("Invalid type expected");
}
}

void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range,
QualifierMangleMode QMM) {
// Don't use the canonical types. MSVC includes things like 'const' on
Expand Down Expand Up @@ -2907,17 +2965,59 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
// can differ by their calling convention and are typically deduced. So
// we make sure that this type gets mangled properly.
mangleType(ResultType, Range, QMM_Result);
} else if (const auto *AT = dyn_cast_or_null<AutoType>(
ResultType->getContainedAutoType())) {
Out << '?';
mangleQualifiers(ResultType.getLocalQualifiers(), /*IsMember=*/false);
Out << '?';
} else if (IsInLambda) {
if (const auto *AT = ResultType->getContainedAutoType()) {
assert(AT->getKeyword() != AutoTypeKeyword::GNUAutoType &&
"shouldn't need to mangle __auto_type!");
Out << '?';
mangleQualifiers(ResultType.getLocalQualifiers(), /*IsMember=*/false);
Out << '?';
mangleSourceName(AT->isDecltypeAuto() ? "<decltype-auto>" : "<auto>");
Out << '@';
} else {
Out << '@';
}
} else if (const auto *AT = ResultType->getContainedAutoType()) {
assert(AT->getKeyword() != AutoTypeKeyword::GNUAutoType &&
"shouldn't need to mangle __auto_type!");
mangleSourceName(AT->isDecltypeAuto() ? "<decltype-auto>" : "<auto>");
Out << '@';
} else if (IsInLambda) {
Out << '@';

// If we have any pointer types with the clang address space extension
// then defer to the custom clang mangling to keep backwards
// compatibility. See `mangleType(const PointerType *T, Qualifiers Quals,
// SourceRange Range)` for details.
auto UseClangMangling = [](QualType ResultType) {
QualType T = ResultType;
while (isa<PointerType>(T.getTypePtr())) {
T = T->getPointeeType();
if (T.getQualifiers().hasAddressSpace())
return true;
}
return false;
};

if (getASTContext().getLangOpts().isCompatibleWithMSVC(
LangOptions::MSVC2019) &&
!UseClangMangling(ResultType)) {
if (D && !D->getPrimaryTemplate()) {
Out << '@';
} else {
if (D && D->getPrimaryTemplate()) {
const FunctionProtoType *FPT = D->getPrimaryTemplate()
->getTemplatedDecl()
->getFirstDecl()
->getType()
->castAs<FunctionProtoType>();
ResultType = FPT->getReturnType();
}
mangleAutoReturnType(ResultType, QMM_Result);
}
} else {
Out << '?';
mangleQualifiers(ResultType.getLocalQualifiers(), /*IsMember=*/false);
Out << '?';
mangleSourceName(AT->isDecltypeAuto() ? "<decltype-auto>" : "<auto>");
Out << '@';
}
} else {
if (ResultType->isVoidType())
ResultType = ResultType.getUnqualifiedType();
Expand Down Expand Up @@ -4220,6 +4320,57 @@ void MicrosoftMangleContextImpl::mangleStringLiteral(const StringLiteral *SL,
Mangler.getStream() << '@';
}

void MicrosoftCXXNameMangler::mangleAutoReturnType(const MemberPointerType *T,
Qualifiers Quals) {
QualType PointeeType = T->getPointeeType();
manglePointerCVQualifiers(Quals);
manglePointerExtQualifiers(Quals, PointeeType);
if (const FunctionProtoType *FPT = PointeeType->getAs<FunctionProtoType>()) {
Out << '8';
mangleName(T->getClass()->castAs<RecordType>()->getDecl());
mangleFunctionType(FPT, nullptr, true);
} else {
mangleQualifiers(PointeeType.getQualifiers(), true);
mangleName(T->getClass()->castAs<RecordType>()->getDecl());
mangleAutoReturnType(PointeeType, QMM_Drop);
}
}

void MicrosoftCXXNameMangler::mangleAutoReturnType(const PointerType *T,
Qualifiers Quals) {
QualType PointeeType = T->getPointeeType();
assert(!PointeeType.getQualifiers().hasAddressSpace() &&
"Unexpected address space mangling required");

manglePointerCVQualifiers(Quals);
manglePointerExtQualifiers(Quals, PointeeType);

if (const FunctionProtoType *FPT = PointeeType->getAs<FunctionProtoType>()) {
Out << '6';
mangleFunctionType(FPT);
} else {
mangleAutoReturnType(PointeeType, QMM_Mangle);
}
}

void MicrosoftCXXNameMangler::mangleAutoReturnType(const LValueReferenceType *T,
Qualifiers Quals) {
QualType PointeeType = T->getPointeeType();
assert(!Quals.hasConst() && !Quals.hasVolatile() && "unexpected qualifier!");
Out << 'A';
manglePointerExtQualifiers(Quals, PointeeType);
mangleAutoReturnType(PointeeType, QMM_Mangle);
}

void MicrosoftCXXNameMangler::mangleAutoReturnType(const RValueReferenceType *T,
Qualifiers Quals) {
QualType PointeeType = T->getPointeeType();
assert(!Quals.hasConst() && !Quals.hasVolatile() && "unexpected qualifier!");
Out << "$$Q";
manglePointerExtQualifiers(Quals, PointeeType);
mangleAutoReturnType(PointeeType, QMM_Mangle);
}

MicrosoftMangleContext *MicrosoftMangleContext::create(ASTContext &Context,
DiagnosticsEngine &Diags,
bool IsAux) {
Expand Down
Loading