22 changes: 22 additions & 0 deletions clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,28 @@ TEST(IncludeCleaner, ResourceDirIsIgnored) {
EXPECT_THAT(Findings.MissingIncludes, IsEmpty());
}

TEST(IncludeCleaner, DifferentHeaderSameSpelling) {
// `foo` is declared in foo_inner/foo.h, but there's no way to spell it
// directly. Make sure we don't generate unusued/missing include findings in
// such cases.
auto TU = TestTU::withCode(R"cpp(
#include <foo.h>
void baz() {
foo();
}
)cpp");
TU.AdditionalFiles["foo/foo.h"] = guard("#include_next <foo.h>");
TU.AdditionalFiles["foo_inner/foo.h"] = guard(R"cpp(
void foo();
)cpp");
TU.ExtraArgs.push_back("-Ifoo");
TU.ExtraArgs.push_back("-Ifoo_inner");

auto AST = TU.build();
auto Findings = computeIncludeCleanerFindings(AST);
EXPECT_THAT(Findings.UnusedIncludes, IsEmpty());
EXPECT_THAT(Findings.MissingIncludes, IsEmpty());
}
} // namespace
} // namespace clangd
} // namespace clang
17 changes: 14 additions & 3 deletions clang-tools-extra/include-cleaner/lib/Analysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,20 @@ analyze(llvm::ArrayRef<Decl *> ASTRoots,
}
if (!Satisfied && !Providers.empty() &&
Ref.RT == RefType::Explicit &&
!HeaderFilter(Providers.front().resolvedPath()))
Missing.insert(spellHeader(
{Providers.front(), PP.getHeaderSearchInfo(), MainFile}));
!HeaderFilter(Providers.front().resolvedPath())) {
// Check if we have any headers with the same spelling, in edge
// cases like `#include_next "foo.h"`, the user can't ever
// include the physical foo.h, but can have a spelling that
// refers to it.
auto Spelling = spellHeader(
{Providers.front(), PP.getHeaderSearchInfo(), MainFile});
for (const Include *I : Inc.match(Header{Spelling})) {
Used.insert(I);
Satisfied = true;
}
if (!Satisfied)
Missing.insert(std::move(Spelling));
}
});

AnalysisResults Results;
Expand Down
26 changes: 26 additions & 0 deletions clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "clang-include-cleaner/Record.h"
#include "clang-include-cleaner/Types.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclBase.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/SourceLocation.h"
Expand Down Expand Up @@ -296,6 +297,31 @@ TEST_F(AnalyzeTest, ResourceDirIsIgnored) {
EXPECT_THAT(Results.Missing, testing::IsEmpty());
}

TEST_F(AnalyzeTest, DifferentHeaderSameSpelling) {
Inputs.ExtraArgs.push_back("-Ifoo");
Inputs.ExtraArgs.push_back("-Ifoo_inner");
// `foo` is declared in foo_inner/foo.h, but there's no way to spell it
// directly. Make sure we don't generate unusued/missing include findings in
// such cases.
Inputs.Code = R"cpp(
#include <foo.h>
void baz() {
foo();
}
)cpp";
Inputs.ExtraFiles["foo/foo.h"] = guard("#include_next <foo.h>");
Inputs.ExtraFiles["foo_inner/foo.h"] = guard(R"cpp(
void foo();
)cpp");
TestAST AST(Inputs);
std::vector<Decl *> DeclsInTU;
for (auto *D : AST.context().getTranslationUnitDecl()->decls())
DeclsInTU.push_back(D);
auto Results = analyze(DeclsInTU, {}, PP.Includes, &PI, AST.preprocessor());
EXPECT_THAT(Results.Unused, testing::IsEmpty());
EXPECT_THAT(Results.Missing, testing::IsEmpty());
}

TEST(FixIncludes, Basic) {
llvm::StringRef Code = R"cpp(#include "d.h"
#include "a.h"
Expand Down
3 changes: 0 additions & 3 deletions clang/cmake/caches/Fuchsia.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,6 @@ set(_FUCHSIA_BOOTSTRAP_PASSTHROUGH
SWIG_EXECUTABLE
CMAKE_FIND_PACKAGE_PREFER_CONFIG
CMAKE_SYSROOT
CMAKE_MODULE_LINKER_FLAGS
CMAKE_SHARED_LINKER_FLAGS
CMAKE_EXE_LINKER_FLAGS
LLVM_WINSYSROOT
LLVM_VFSOVERLAY
)
Expand Down
130 changes: 130 additions & 0 deletions clang/docs/MSVCCompatibility.rst
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,133 @@ a hint suggesting how to fix the problem.
As of this writing, Clang is able to compile a simple ATL hello world
application. There are still issues parsing WRL headers for modern Windows 8
apps, but they should be addressed soon.

__forceinline behavior
======================

``__forceinline`` behaves like ``[[clang::always_inline]]``.
Inlining is always attempted regardless of optimization level.

This differs from MSVC where ``__forceinline`` is only respected once inline expansion is enabled
which allows any function marked implicitly or explicitly ``inline`` or ``__forceinline`` to be expanded.
Therefore functions marked ``__forceinline`` will be expanded when the optimization level is ``/Od`` unlike
MSVC where ``__forceinline`` will not be expanded under ``/Od``.

SIMD and instruction set intrinsic behavior
===========================================

Clang follows the GCC model for intrinsics and not the MSVC model.
There are currently no plans to support the MSVC model.

MSVC intrinsics always emit the machine instruction the intrinsic models regardless of the compile time options specified.
For example ``__popcnt`` always emits the x86 popcnt instruction even if the compiler does not have the option enabled to emit popcnt on its own volition.

There are two common cases where code that compiles with MSVC will need reworking to build on clang.
Assume the examples are only built with `-msse2` so we do not have the intrinsics at compile time.

.. code-block:: c++

unsigned PopCnt(unsigned v) {
if (HavePopCnt)
return __popcnt(v);
else
return GenericPopCnt(v);
}

.. code-block:: c++

__m128 dot4_sse3(__m128 v0, __m128 v1) {
__m128 r = _mm_mul_ps(v0, v1);
r = _mm_hadd_ps(r, r);
r = _mm_hadd_ps(r, r);
return r;
}

Clang expects that either you have compile time support for the target features, `-msse3` and `-mpopcnt`, you mark the function with the expected target feature or use runtime detection with an indirect call.

.. code-block:: c++

__attribute__((__target__("sse3"))) __m128 dot4_sse3(__m128 v0, __m128 v1) {
__m128 r = _mm_mul_ps(v0, v1);
r = _mm_hadd_ps(r, r);
r = _mm_hadd_ps(r, r);
return r;
}

The SSE3 dot product can be easily fixed by either building the translation unit with SSE3 support or using `__target__` to compile that specific function with SSE3 support.

.. code-block:: c++

unsigned PopCnt(unsigned v) {
if (HavePopCnt)
return __popcnt(v);
else
return GenericPopCnt(v);
}

The above ``PopCnt`` example must be changed to work with clang. If we mark the function with `__target__("popcnt")` then the compiler is free to emit popcnt at will which we do not want. While this isn't a concern in our small example it is a concern in larger functions with surrounding code around the intrinsics. Similar reasoning for compiling the translation unit with `-mpopcnt`.
We must split each branch into its own function that can be called indirectly instead of using the intrinsic directly.

.. code-block:: c++

__attribute__((__target__("popcnt"))) unsigned hwPopCnt(unsigned v) { return __popcnt(v); }
unsigned (*PopCnt)(unsigned) = HavePopCnt ? hwPopCnt : GenericPopCnt;
.. code-block:: c++

__attribute__((__target__("popcnt"))) unsigned hwPopCnt(unsigned v) { return __popcnt(v); }
unsigned PopCnt(unsigned v) {
if (HavePopCnt)
return hwPopCnt(v);
else
return GenericPopCnt(v);
}

In the above example ``hwPopCnt`` will not be inlined into ``PopCnt`` since ``PopCnt`` doesn't have the popcnt target feature.
With a larger function that does real work the function call overhead is negligible. However in our popcnt example there is the function call
overhead. There is no analog for this specific MSVC behavior in clang.

For clang we effectively have to create the dispatch function ourselves to each specfic implementation.

SIMD vector types
=================

Clang's simd vector types are builtin types and not user defined types as in MSVC. This does have some observable behavior changes.
We will look at the x86 `__m128` type for the examples below but the statements apply to all vector types including ARM's `float32x4_t`.

There are no members that can be accessed on the vector types. Vector types are not structs in clang.
You cannot use ``__m128.m128_f32[0]`` to access the first element of the `__m128`.
This also means struct initialization like ``__m128{ { 0.0f, 0.0f, 0.0f, 0.0f } }`` will not compile with clang.

Since vector types are builtin types, clang implements operators on them natively.

.. code-block:: c++

#ifdef _MSC_VER
__m128 operator+(__m128 a, __m128 b) { return _mm_add_ps(a, b); }
#endif

The above code will fail to compile since overloaded 'operator+' must have at least one parameter of class or enumeration type.
You will need to fix such code to have the check ``#if defined(_MSC_VER) && !defined(__clang__)``.

Since `__m128` is not a class type in clang any overloads after a template definition will not be considered.

.. code-block:: c++

template<class T>
void foo(T) {}

template<class T>
void bar(T t) {
foo(t);
}

void foo(__m128) {}

int main() {
bar(_mm_setzero_ps());
}

With MSVC ``foo(__m128)`` will be selected but with clang ``foo<__m128>()`` will be selected since on clang `__m128` is a builtin type.

In general the takeaway is `__m128` is a builtin type on clang while a class type on MSVC.
16 changes: 15 additions & 1 deletion clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ C++ Specific Potentially Breaking Changes
versions of clang. The deprecation warning for the negative spelling can be
disabled with `-Wno-deprecated-no-relaxed-template-template-args`.

- Clang now rejects pointer to member from parenthesized expression in unevaluated context such as ``decltype(&(foo::bar))``. (#GH40906).
- Clang no longer tries to form pointer-to-members from qualified and parenthesized unevaluated expressions
such as ``decltype(&(foo::bar))``. (#GH40906).

- Clang now performs semantic analysis for unary operators with dependent operands
that are known to be of non-class non-enumeration type prior to instantiation.
Expand Down Expand Up @@ -743,6 +744,19 @@ Improvements to Clang's diagnostics

- Clang now diagnoses dangling assignments for pointer-like objects (annotated with `[[gsl::Pointer]]`) under `-Wdangling-assignment-gsl` (off by default)
Fixes #GH63310.

- Clang now diagnoses uses of alias templates with a deprecated attribute. (Fixes #GH18236).

.. code-block:: c++

template <typename T>
struct NoAttr {
};

template <typename T>
using UsingWithAttr __attribute__((deprecated)) = NoAttr<T>;

UsingWithAttr<int> objUsingWA; // warning: 'UsingWithAttr' is deprecated

Improvements to Clang's time-trace
----------------------------------
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -902,7 +902,7 @@ def PatchableFunctionEntry
: InheritableAttr,
TargetSpecificAttr<TargetArch<
["aarch64", "aarch64_be", "loongarch32", "loongarch64", "riscv32",
"riscv64", "x86", "x86_64"]>> {
"riscv64", "x86", "x86_64", "ppc", "ppc64"]>> {
let Spellings = [GCC<"patchable_function_entry">];
let Subjects = SubjectList<[Function, ObjCMethod]>;
let Args = [UnsignedArgument<"Count">, DefaultIntArgument<"Offset", 0>];
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -5800,7 +5800,8 @@ takes precedence over the command line option ``-fpatchable-function-entry=N,M``
``M`` defaults to 0 if omitted.

This attribute is only supported on
aarch64/aarch64-be/loongarch32/loongarch64/riscv32/riscv64/i386/x86-64 targets.
aarch64/aarch64-be/loongarch32/loongarch64/riscv32/riscv64/i386/x86-64/ppc/ppc64 targets.
For ppc/ppc64 targets, AIX is still not supported.
}];
}

Expand Down
5 changes: 1 addition & 4 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -3492,7 +3492,7 @@ def err_attr_tlsmodel_arg : Error<"tls_model must be \"global-dynamic\", "

def err_attr_codemodel_arg : Error<"code model '%0' is not supported on this target">;

def err_aix_attr_unsupported_tls_model : Error<"TLS model '%0' is not yet supported on AIX">;
def err_aix_attr_unsupported : Error<"%0 attribute is not yet supported on AIX">;

def err_tls_var_aligned_over_maximum : Error<
"alignment (%0) of thread-local variable %1 is greater than the maximum supported "
Expand Down Expand Up @@ -7596,9 +7596,6 @@ def err_nested_non_static_member_use : Error<
def warn_cxx98_compat_non_static_member_use : Warning<
"use of non-static data member %0 in an unevaluated context is "
"incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore;
def err_form_ptr_to_member_from_parenthesized_expr : Error<
"cannot form pointer to member from a parenthesized expression; "
"did you mean to remove the parentheses?">;
def err_invalid_incomplete_type_use : Error<
"invalid use of incomplete type %0">;
def err_builtin_func_cast_more_than_one_arg : Error<
Expand Down
64 changes: 32 additions & 32 deletions clang/include/clang/Basic/arm_neon.td
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ def SPLATQ : WInst<"splat_laneq", ".(!Q)I",
"UcUsUicsilPcPsfQUcQUsQUiQcQsQiQPcQPsQflUlQlQUlhdQhQdPlQPl"> {
let isLaneQ = 1;
}
let TargetGuard = "bf16" in {
let TargetGuard = "bf16,neon" in {
def SPLAT_BF : WInst<"splat_lane", ".(!q)I", "bQb">;
def SPLATQ_BF : WInst<"splat_laneq", ".(!Q)I", "bQb"> {
let isLaneQ = 1;
Expand Down Expand Up @@ -323,7 +323,7 @@ def VMLSL : SOpInst<"vmlsl", "(>Q)(>Q)..", "csiUcUsUi", OP_MLSL>;
def VQDMULH : SInst<"vqdmulh", "...", "siQsQi">;
def VQRDMULH : SInst<"vqrdmulh", "...", "siQsQi">;

let TargetGuard = "v8.1a" in {
let TargetGuard = "v8.1a,neon" in {
def VQRDMLAH : SInst<"vqrdmlah", "....", "siQsQi">;
def VQRDMLSH : SInst<"vqrdmlsh", "....", "siQsQi">;
}
Expand Down Expand Up @@ -614,7 +614,7 @@ def A64_VQDMULH_LANE : SInst<"vqdmulh_lane", "..(!q)I", "siQsQi">;
def A64_VQRDMULH_LANE : SInst<"vqrdmulh_lane", "..(!q)I", "siQsQi">;
}

let TargetGuard = "v8.1a" in {
let TargetGuard = "v8.1a,neon" in {
def VQRDMLAH_LANE : SOpInst<"vqrdmlah_lane", "...qI", "siQsQi", OP_QRDMLAH_LN>;
def VQRDMLSH_LANE : SOpInst<"vqrdmlsh_lane", "...qI", "siQsQi", OP_QRDMLSH_LN>;
}
Expand Down Expand Up @@ -957,7 +957,7 @@ def VQDMLAL_HIGH : SOpInst<"vqdmlal_high", "(>Q)(>Q)QQ", "si", OP_QDMLALHi>;
def VQDMLAL_HIGH_N : SOpInst<"vqdmlal_high_n", "(>Q)(>Q)Q1", "si", OP_QDMLALHi_N>;
def VQDMLSL_HIGH : SOpInst<"vqdmlsl_high", "(>Q)(>Q)QQ", "si", OP_QDMLSLHi>;
def VQDMLSL_HIGH_N : SOpInst<"vqdmlsl_high_n", "(>Q)(>Q)Q1", "si", OP_QDMLSLHi_N>;
let TargetGuard = "aes" in {
let TargetGuard = "aes,neon" in {
def VMULL_P64 : SInst<"vmull", "(1>)11", "Pl">;
def VMULL_HIGH_P64 : SOpInst<"vmull_high", "(1>)..", "HPl", OP_MULLHi_P64>;
}
Expand Down Expand Up @@ -1091,7 +1091,7 @@ let isLaneQ = 1 in {
def VQDMULH_LANEQ : SInst<"vqdmulh_laneq", "..QI", "siQsQi">;
def VQRDMULH_LANEQ : SInst<"vqrdmulh_laneq", "..QI", "siQsQi">;
}
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "v8.1a" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "v8.1a,neon" in {
def VQRDMLAH_LANEQ : SOpInst<"vqrdmlah_laneq", "...QI", "siQsQi", OP_QRDMLAH_LN> {
let isLaneQ = 1;
}
Expand Down Expand Up @@ -1122,14 +1122,14 @@ def VEXT_A64 : WInst<"vext", "...I", "dQdPlQPl">;

////////////////////////////////////////////////////////////////////////////////
// Crypto
let ArchGuard = "__ARM_ARCH >= 8", TargetGuard = "aes" in {
let ArchGuard = "__ARM_ARCH >= 8", TargetGuard = "aes,neon" in {
def AESE : SInst<"vaese", "...", "QUc">;
def AESD : SInst<"vaesd", "...", "QUc">;
def AESMC : SInst<"vaesmc", "..", "QUc">;
def AESIMC : SInst<"vaesimc", "..", "QUc">;
}

let ArchGuard = "__ARM_ARCH >= 8", TargetGuard = "sha2" in {
let ArchGuard = "__ARM_ARCH >= 8", TargetGuard = "sha2,neon" in {
def SHA1H : SInst<"vsha1h", "11", "Ui">;
def SHA1SU1 : SInst<"vsha1su1", "...", "QUi">;
def SHA256SU0 : SInst<"vsha256su0", "...", "QUi">;
Expand All @@ -1143,7 +1143,7 @@ def SHA256H2 : SInst<"vsha256h2", "....", "QUi">;
def SHA256SU1 : SInst<"vsha256su1", "....", "QUi">;
}

let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "sha3" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "sha3,neon" in {
def BCAX : SInst<"vbcax", "....", "QUcQUsQUiQUlQcQsQiQl">;
def EOR3 : SInst<"veor3", "....", "QUcQUsQUiQUlQcQsQiQl">;
def RAX1 : SInst<"vrax1", "...", "QUl">;
Expand All @@ -1153,14 +1153,14 @@ def XAR : SInst<"vxar", "...I", "QUl">;
}
}

let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "sha3" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "sha3,neon" in {
def SHA512SU0 : SInst<"vsha512su0", "...", "QUl">;
def SHA512su1 : SInst<"vsha512su1", "....", "QUl">;
def SHA512H : SInst<"vsha512h", "....", "QUl">;
def SHA512H2 : SInst<"vsha512h2", "....", "QUl">;
}

let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "sm4" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "sm4,neon" in {
def SM3SS1 : SInst<"vsm3ss1", "....", "QUi">;
def SM3TT1A : SInst<"vsm3tt1a", "....I", "QUi">;
def SM3TT1B : SInst<"vsm3tt1b", "....I", "QUi">;
Expand All @@ -1170,7 +1170,7 @@ def SM3PARTW1 : SInst<"vsm3partw1", "....", "QUi">;
def SM3PARTW2 : SInst<"vsm3partw2", "....", "QUi">;
}

let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "sm4" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "sm4,neon" in {
def SM4E : SInst<"vsm4e", "...", "QUi">;
def SM4EKEY : SInst<"vsm4ekey", "...", "QUi">;
}
Expand Down Expand Up @@ -1227,7 +1227,7 @@ def FRINTZ_S64 : SInst<"vrnd", "..", "dQd">;
def FRINTI_S64 : SInst<"vrndi", "..", "dQd">;
}

let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "v8.5a" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "v8.5a,neon" in {
def FRINT32X_S32 : SInst<"vrnd32x", "..", "fQf">;
def FRINT32Z_S32 : SInst<"vrnd32z", "..", "fQf">;
def FRINT64X_S32 : SInst<"vrnd64x", "..", "fQf">;
Expand Down Expand Up @@ -1401,7 +1401,7 @@ def SCALAR_SQDMULH : SInst<"vqdmulh", "111", "SsSi">;
// Scalar Integer Saturating Rounding Doubling Multiply Half High
def SCALAR_SQRDMULH : SInst<"vqrdmulh", "111", "SsSi">;

let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "v8.1a" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "v8.1a,neon" in {
////////////////////////////////////////////////////////////////////////////////
// Signed Saturating Rounding Doubling Multiply Accumulate Returning High Half
def SCALAR_SQRDMLAH : SInst<"vqrdmlah", "1111", "SsSi">;
Expand Down Expand Up @@ -1632,7 +1632,7 @@ def SCALAR_SQRDMULH_LANEQ : SOpInst<"vqrdmulh_laneq", "11QI", "SsSi", OP_SCALAR_
let isLaneQ = 1;
}

let TargetGuard = "v8.1a" in {
let TargetGuard = "v8.1a,neon" in {
// Signed Saturating Rounding Doubling Multiply Accumulate Returning High Half
def SCALAR_SQRDMLAH_LANE : SOpInst<"vqrdmlah_lane", "111.I", "SsSi", OP_SCALAR_QRDMLAH_LN>;
def SCALAR_SQRDMLAH_LANEQ : SOpInst<"vqrdmlah_laneq", "111QI", "SsSi", OP_SCALAR_QRDMLAH_LN> {
Expand All @@ -1654,7 +1654,7 @@ def SCALAR_VDUP_LANEQ : IInst<"vdup_laneq", "1QI", "ScSsSiSlSfSdSUcSUsSUiSUlSPcS
} // ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)"

// ARMv8.2-A FP16 vector intrinsics for A32/A64.
let TargetGuard = "fullfp16" in {
let TargetGuard = "fullfp16,neon" in {

// ARMv8.2-A FP16 one-operand vector intrinsics.

Expand All @@ -1679,7 +1679,7 @@ let TargetGuard = "fullfp16" in {
def VCVTP_U16 : SInst<"vcvtp_u16", "U.", "hQh">;

// Vector rounding
let ArchGuard = "__ARM_ARCH >= 8 && defined(__ARM_FEATURE_DIRECTED_ROUNDING)", TargetGuard = "fullfp16" in {
let ArchGuard = "__ARM_ARCH >= 8 && defined(__ARM_FEATURE_DIRECTED_ROUNDING)", TargetGuard = "fullfp16,neon" in {
def FRINTZH : SInst<"vrnd", "..", "hQh">;
def FRINTNH : SInst<"vrndn", "..", "hQh">;
def FRINTAH : SInst<"vrnda", "..", "hQh">;
Expand Down Expand Up @@ -1728,7 +1728,7 @@ let TargetGuard = "fullfp16" in {
// Max/Min
def VMAXH : SInst<"vmax", "...", "hQh">;
def VMINH : SInst<"vmin", "...", "hQh">;
let ArchGuard = "__ARM_ARCH >= 8 && defined(__ARM_FEATURE_NUMERIC_MAXMIN)", TargetGuard = "fullfp16" in {
let ArchGuard = "__ARM_ARCH >= 8 && defined(__ARM_FEATURE_NUMERIC_MAXMIN)", TargetGuard = "fullfp16,neon" in {
def FMAXNMH : SInst<"vmaxnm", "...", "hQh">;
def FMINNMH : SInst<"vminnm", "...", "hQh">;
}
Expand Down Expand Up @@ -1775,7 +1775,7 @@ def VEXTH : WInst<"vext", "...I", "hQh">;
def VREV64H : WOpInst<"vrev64", "..", "hQh", OP_REV64>;

// ARMv8.2-A FP16 vector intrinsics for A64 only.
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "fullfp16" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "fullfp16,neon" in {

// Vector rounding
def FRINTIH : SInst<"vrndi", "..", "hQh">;
Expand Down Expand Up @@ -1872,19 +1872,19 @@ let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)" in {
}

// v8.2-A dot product instructions.
let TargetGuard = "dotprod" in {
let TargetGuard = "dotprod,neon" in {
def DOT : SInst<"vdot", "..(<<)(<<)", "iQiUiQUi">;
def DOT_LANE : SOpInst<"vdot_lane", "..(<<)(<<q)I", "iUiQiQUi", OP_DOT_LN>;
}
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "dotprod" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "dotprod,neon" in {
// Variants indexing into a 128-bit vector are A64 only.
def UDOT_LANEQ : SOpInst<"vdot_laneq", "..(<<)(<<Q)I", "iUiQiQUi", OP_DOT_LNQ> {
let isLaneQ = 1;
}
}

// v8.2-A FP16 fused multiply-add long instructions.
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "fp16fml" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "fp16fml,neon" in {
def VFMLAL_LOW : SInst<"vfmlal_low", ">>..", "hQh">;
def VFMLSL_LOW : SInst<"vfmlsl_low", ">>..", "hQh">;
def VFMLAL_HIGH : SInst<"vfmlal_high", ">>..", "hQh">;
Expand All @@ -1909,7 +1909,7 @@ let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "f
}
}

let TargetGuard = "i8mm" in {
let TargetGuard = "i8mm,neon" in {
def VMMLA : SInst<"vmmla", "..(<<)(<<)", "QUiQi">;
def VUSMMLA : SInst<"vusmmla", "..(<<U)(<<)", "Qi">;

Expand All @@ -1926,7 +1926,7 @@ let TargetGuard = "i8mm" in {
}
}

let TargetGuard = "bf16" in {
let TargetGuard = "bf16,neon" in {
def VDOT_BF : SInst<"vbfdot", "..BB", "fQf">;
def VDOT_LANE_BF : SOpInst<"vbfdot_lane", "..B(Bq)I", "fQf", OP_BFDOT_LN>;
def VDOT_LANEQ_BF : SOpInst<"vbfdot_laneq", "..B(BQ)I", "fQf", OP_BFDOT_LNQ> {
Expand Down Expand Up @@ -1970,31 +1970,31 @@ multiclass VCMLA_ROTS<string type, string lanety, string laneqty> {
}

// v8.3-A Vector complex addition intrinsics
let TargetGuard = "v8.3a,fullfp16" in {
let TargetGuard = "v8.3a,fullfp16,neon" in {
def VCADD_ROT90_FP16 : SInst<"vcadd_rot90", "...", "h">;
def VCADD_ROT270_FP16 : SInst<"vcadd_rot270", "...", "h">;
def VCADDQ_ROT90_FP16 : SInst<"vcaddq_rot90", "QQQ", "h">;
def VCADDQ_ROT270_FP16 : SInst<"vcaddq_rot270", "QQQ", "h">;

defm VCMLA_FP16 : VCMLA_ROTS<"h", "uint32x2_t", "uint32x4_t">;
}
let TargetGuard = "v8.3a" in {
let TargetGuard = "v8.3a,neon" in {
def VCADD_ROT90 : SInst<"vcadd_rot90", "...", "f">;
def VCADD_ROT270 : SInst<"vcadd_rot270", "...", "f">;
def VCADDQ_ROT90 : SInst<"vcaddq_rot90", "QQQ", "f">;
def VCADDQ_ROT270 : SInst<"vcaddq_rot270", "QQQ", "f">;

defm VCMLA_F32 : VCMLA_ROTS<"f", "uint64x1_t", "uint64x2_t">;
}
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "v8.3a" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "v8.3a,neon" in {
def VCADDQ_ROT90_FP64 : SInst<"vcaddq_rot90", "QQQ", "d">;
def VCADDQ_ROT270_FP64 : SInst<"vcaddq_rot270", "QQQ", "d">;

defm VCMLA_FP64 : VCMLA_ROTS<"d", "uint64x2_t", "uint64x2_t">;
}

// V8.2-A BFloat intrinsics
let TargetGuard = "bf16" in {
let TargetGuard = "bf16,neon" in {
def VCREATE_BF : NoTestOpInst<"vcreate", ".(IU>)", "b", OP_CAST> {
let BigEndianSafe = 1;
}
Expand Down Expand Up @@ -2058,14 +2058,14 @@ let TargetGuard = "bf16" in {
def SCALAR_CVT_F32_BF16 : SOpInst<"vcvtah_f32", "(1F>)(1!)", "b", OP_CVT_F32_BF16>;
}

let ArchGuard = "!defined(__aarch64__) && !defined(__arm64ec__)", TargetGuard = "bf16" in {
let ArchGuard = "!defined(__aarch64__) && !defined(__arm64ec__)", TargetGuard = "bf16,neon" in {
def VCVT_BF16_F32_A32_INTERNAL : WInst<"__a32_vcvt_bf16", "BQ", "f">;
def VCVT_BF16_F32_A32 : SOpInst<"vcvt_bf16", "BQ", "f", OP_VCVT_BF16_F32_A32>;
def VCVT_LOW_BF16_F32_A32 : SOpInst<"vcvt_low_bf16", "BQ", "Qf", OP_VCVT_BF16_F32_LO_A32>;
def VCVT_HIGH_BF16_F32_A32 : SOpInst<"vcvt_high_bf16", "BBQ", "Qf", OP_VCVT_BF16_F32_HI_A32>;
}

let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "bf16" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "bf16,neon" in {
def VCVT_LOW_BF16_F32_A64_INTERNAL : WInst<"__a64_vcvtq_low_bf16", "BQ", "Hf">;
def VCVT_LOW_BF16_F32_A64 : SOpInst<"vcvt_low_bf16", "BQ", "Qf", OP_VCVT_BF16_F32_LO_A64>;
def VCVT_HIGH_BF16_F32_A64 : SInst<"vcvt_high_bf16", "BBQ", "Qf">;
Expand All @@ -2077,22 +2077,22 @@ let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "b
def COPYQ_LANEQ_BF16 : IOpInst<"vcopy_laneq", "..I.I", "Qb", OP_COPY_LN>;
}

let ArchGuard = "!defined(__aarch64__) && !defined(__arm64ec__)", TargetGuard = "bf16" in {
let ArchGuard = "!defined(__aarch64__) && !defined(__arm64ec__)", TargetGuard = "bf16,neon" in {
let BigEndianSafe = 1 in {
defm VREINTERPRET_BF : REINTERPRET_CROSS_TYPES<
"csilUcUsUiUlhfPcPsPlQcQsQiQlQUcQUsQUiQUlQhQfQPcQPsQPl", "bQb">;
}
}

let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "bf16" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "bf16,neon" in {
let BigEndianSafe = 1 in {
defm VVREINTERPRET_BF : REINTERPRET_CROSS_TYPES<
"csilUcUsUiUlhfdPcPsPlQcQsQiQlQUcQUsQUiQUlQhQfQdQPcQPsQPlQPk", "bQb">;
}
}

// v8.9a/v9.4a LRCPC3 intrinsics
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "rcpc3" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "rcpc3,neon" in {
def VLDAP1_LANE : WInst<"vldap1_lane", ".(c*!).I", "QUlQlUlldQdPlQPl">;
def VSTL1_LANE : WInst<"vstl1_lane", "v*(.!)I", "QUlQlUlldQdPlQPl">;
}
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/arm_neon_incl.td
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ class Inst <string n, string p, string t, Operation o> {
string Prototype = p;
string Types = t;
string ArchGuard = "";
string TargetGuard = "";
string TargetGuard = "neon";

Operation Operation = o;
bit BigEndianSafe = 0;
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/Boolean.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class Boolean final {
APSInt toAPSInt(unsigned NumBits) const {
return APSInt(toAPSInt().zextOrTrunc(NumBits), true);
}
APValue toAPValue() const { return APValue(toAPSInt()); }
APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); }

Boolean toUnsigned() const { return *this; }

Expand Down
4 changes: 1 addition & 3 deletions clang/lib/AST/Interp/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1698,10 +1698,8 @@ bool Compiler<Emitter>::VisitUnaryExprOrTypeTraitExpr(
if (Kind == UETT_VectorElements) {
if (const auto *VT = E->getTypeOfArgument()->getAs<VectorType>())
return this->emitConst(VT->getNumElements(), E);

// FIXME: Apparently we need to catch the fact that a sizeless vector type
// has been passed and diagnose that (at run time).
assert(E->getTypeOfArgument()->isSizelessVectorType());
return this->emitSizelessVectorElementSize(E);
}

if (Kind == UETT_VecStep) {
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/AST/Interp/Disasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -366,9 +366,9 @@ LLVM_DUMP_METHOD void EvaluationResult::dump() const {

OS << "LValue: ";
if (const auto *P = std::get_if<Pointer>(&Value))
P->toAPValue().printPretty(OS, ASTCtx, SourceType);
P->toAPValue(ASTCtx).printPretty(OS, ASTCtx, SourceType);
else if (const auto *FP = std::get_if<FunctionPointer>(&Value)) // Nope
FP->toAPValue().printPretty(OS, ASTCtx, SourceType);
FP->toAPValue(ASTCtx).printPretty(OS, ASTCtx, SourceType);
OS << "\n";
break;
}
Expand Down
11 changes: 7 additions & 4 deletions clang/lib/AST/Interp/EvalEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ template <PrimType OpType> bool EvalEmitter::emitRet(const SourceInfo &Info) {
return false;

using T = typename PrimConv<OpType>::T;
EvalResult.setValue(S.Stk.pop<T>().toAPValue());
EvalResult.setValue(S.Stk.pop<T>().toAPValue(Ctx.getASTContext()));
return true;
}

Expand All @@ -169,7 +169,9 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) {
return false;
// Never allow reading from a non-const pointer, unless the memory
// has been created in this evaluation.
if (!Ptr.isConst() && Ptr.block()->getEvalID() != Ctx.getEvalID())
if (!Ptr.isZero() && Ptr.isBlockPointer() &&
Ptr.block()->getEvalID() != Ctx.getEvalID() &&
(!CheckLoad(S, OpPC, Ptr, AK_Read) || !Ptr.isConst()))
return false;

if (std::optional<APValue> V =
Expand All @@ -179,7 +181,7 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) {
return false;
}
} else {
EvalResult.setValue(Ptr.toAPValue());
EvalResult.setValue(Ptr.toAPValue(Ctx.getASTContext()));
}

return true;
Expand Down Expand Up @@ -283,7 +285,8 @@ void EvalEmitter::updateGlobalTemporaries() {
APValue *Cached = Temp->getOrCreateValue(true);

if (std::optional<PrimType> T = Ctx.classify(E->getType())) {
TYPE_SWITCH(*T, { *Cached = Ptr.deref<T>().toAPValue(); });
TYPE_SWITCH(
*T, { *Cached = Ptr.deref<T>().toAPValue(Ctx.getASTContext()); });
} else {
if (std::optional<APValue> APV =
Ptr.toRValue(Ctx, Temp->getTemporaryExpr()->getType()))
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/AST/Interp/EvaluationResult.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ APValue EvaluationResult::toAPValue() const {
case LValue:
// Either a pointer or a function pointer.
if (const auto *P = std::get_if<Pointer>(&Value))
return P->toAPValue();
return P->toAPValue(Ctx->getASTContext());
else if (const auto *FP = std::get_if<FunctionPointer>(&Value))
return FP->toAPValue();
return FP->toAPValue(Ctx->getASTContext());
else
llvm_unreachable("Unhandled LValue type");
break;
Expand All @@ -46,7 +46,7 @@ std::optional<APValue> EvaluationResult::toRValue() const {
if (const auto *P = std::get_if<Pointer>(&Value))
return P->toRValue(*Ctx, getSourceType());
else if (const auto *FP = std::get_if<FunctionPointer>(&Value)) // Nope
return FP->toAPValue();
return FP->toAPValue(Ctx->getASTContext());
llvm_unreachable("Unhandled lvalue kind");
}

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/Floating.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class Floating final {
APSInt toAPSInt(unsigned NumBits = 0) const {
return APSInt(F.bitcastToAPInt());
}
APValue toAPValue() const { return APValue(F); }
APValue toAPValue(const ASTContext &) const { return APValue(F); }
void print(llvm::raw_ostream &OS) const {
// Can't use APFloat::print() since it appends a newline.
SmallVector<char, 16> Buffer;
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/AST/Interp/FunctionPointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class FunctionPointer final {
return Func->getDecl()->isWeak();
}

APValue toAPValue() const {
APValue toAPValue(const ASTContext &) const {
if (!Func)
return APValue(static_cast<Expr *>(nullptr), CharUnits::Zero(), {},
/*OnePastTheEnd=*/false, /*IsNull=*/true);
Expand Down Expand Up @@ -69,7 +69,7 @@ class FunctionPointer final {
if (!Func)
return "nullptr";

return toAPValue().getAsString(Ctx, Func->getDecl()->getType());
return toAPValue(Ctx).getAsString(Ctx, Func->getDecl()->getType());
}

uint64_t getIntegerRepresentation() const {
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/Integral.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ template <unsigned Bits, bool Signed> class Integral final {
else
return APSInt(toAPSInt().zextOrTrunc(NumBits), !Signed);
}
APValue toAPValue() const { return APValue(toAPSInt()); }
APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); }

Integral<Bits, false> toUnsigned() const {
return Integral<Bits, false>(*this);
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/IntegralAP.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ template <bool Signed> class IntegralAP final {
else
return APSInt(V.zext(Bits), !Signed);
}
APValue toAPValue() const { return APValue(toAPSInt()); }
APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); }

bool isZero() const { return V.isZero(); }
bool isPositive() const { return V.isNonNegative(); }
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/AST/Interp/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -728,8 +728,8 @@ bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC) {
return true;

const SourceInfo &E = S.Current->getSource(OpPC);
S.FFDiag(E, diag::note_constexpr_new);
return false;
S.CCEDiag(E, diag::note_constexpr_new);
return true;
}

bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, bool NewWasArray,
Expand Down
18 changes: 14 additions & 4 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,9 @@ namespace interp {
using APSInt = llvm::APSInt;

/// Convert a value to an APValue.
template <typename T> bool ReturnValue(const T &V, APValue &R) {
R = V.toAPValue();
template <typename T>
bool ReturnValue(const InterpState &S, const T &V, APValue &R) {
R = V.toAPValue(S.getCtx());
return true;
}

Expand Down Expand Up @@ -286,7 +287,7 @@ bool Ret(InterpState &S, CodePtr &PC, APValue &Result) {
} else {
delete S.Current;
S.Current = nullptr;
if (!ReturnValue<T>(Ret, Result))
if (!ReturnValue<T>(S, Ret, Result))
return false;
}
return true;
Expand Down Expand Up @@ -1318,7 +1319,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();
APValue APV = Value.toAPValue(S.getCtx());
APValue *Cached = Temp->getOrCreateValue(true);
*Cached = APV;

Expand Down Expand Up @@ -2735,6 +2736,15 @@ inline bool InvalidDeclRef(InterpState &S, CodePtr OpPC,
return CheckDeclRef(S, OpPC, DR);
}

inline bool SizelessVectorElementSize(InterpState &S, CodePtr OpPC) {
if (S.inConstantContext()) {
const SourceRange &ArgRange = S.Current->getRange(OpPC);
const Expr *E = S.Current->getExpr(OpPC);
S.CCEDiag(E, diag::note_constexpr_non_const_vectorelements) << ArgRange;
}
return false;
}

inline bool Assume(InterpState &S, CodePtr OpPC) {
const auto Val = S.Stk.pop<Boolean>();

Expand Down
4 changes: 2 additions & 2 deletions clang/lib/AST/Interp/MemberPointer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,13 @@ FunctionPointer MemberPointer::toFunctionPointer(const Context &Ctx) const {
return FunctionPointer(Ctx.getProgram().getFunction(cast<FunctionDecl>(Dcl)));
}

APValue MemberPointer::toAPValue() const {
APValue MemberPointer::toAPValue(const ASTContext &ASTCtx) const {
if (isZero())
return APValue(static_cast<ValueDecl *>(nullptr), /*IsDerivedMember=*/false,
/*Path=*/{});

if (hasBase())
return Base.toAPValue();
return Base.toAPValue(ASTCtx);

return APValue(cast<ValueDecl>(getDecl()), /*IsDerivedMember=*/false,
/*Path=*/{});
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/MemberPointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ class MemberPointer final {
return MemberPointer(Instance, this->Dcl, this->PtrOffset);
}

APValue toAPValue() const;
APValue toAPValue(const ASTContext &) const;

bool isZero() const { return Base.isZero() && !Dcl; }
bool hasBase() const { return !Base.isZero(); }
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/Interp/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,8 @@ def InvalidDeclRef : Opcode {
let Args = [ArgDeclRef];
}

def SizelessVectorElementSize : Opcode;

def Assume : Opcode;

def ArrayDecay : Opcode;
Expand Down
83 changes: 56 additions & 27 deletions clang/lib/AST/Interp/Pointer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "MemberPointer.h"
#include "PrimType.h"
#include "Record.h"
#include "clang/AST/RecordLayout.h"

using namespace clang;
using namespace clang::interp;
Expand Down Expand Up @@ -119,7 +120,7 @@ void Pointer::operator=(Pointer &&P) {
}
}

APValue Pointer::toAPValue() const {
APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
llvm::SmallVector<APValue::LValuePathEntry, 5> Path;

if (isZero())
Expand All @@ -141,25 +142,42 @@ APValue Pointer::toAPValue() const {
else
llvm_unreachable("Invalid allocation type");

if (isDummy() || isUnknownSizeArray() || Desc->asExpr())
if (isUnknownSizeArray() || Desc->asExpr())
return APValue(Base, CharUnits::Zero(), Path,
/*IsOnePastEnd=*/isOnePastEnd(), /*IsNullPtr=*/false);

// TODO: compute the offset into the object.
CharUnits Offset = CharUnits::Zero();

auto getFieldOffset = [&](const FieldDecl *FD) -> CharUnits {
// This shouldn't happen, but if it does, don't crash inside
// getASTRecordLayout.
if (FD->getParent()->isInvalidDecl())
return CharUnits::Zero();
const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent());
unsigned FieldIndex = FD->getFieldIndex();
return ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex));
};

// Build the path into the object.
Pointer Ptr = *this;
while (Ptr.isField() || Ptr.isArrayElement()) {
if (Ptr.isArrayRoot()) {
Path.push_back(APValue::LValuePathEntry(
{Ptr.getFieldDesc()->asDecl(), /*IsVirtual=*/false}));

if (const auto *FD = dyn_cast<FieldDecl>(Ptr.getFieldDesc()->asDecl()))
Offset += getFieldOffset(FD);

Ptr = Ptr.getBase();
} else if (Ptr.isArrayElement()) {
unsigned Index;
if (Ptr.isOnePastEnd())
Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getArray().getNumElems()));
Index = Ptr.getArray().getNumElems();
else
Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getIndex()));
Index = Ptr.getIndex();

Offset += (Index * ASTCtx.getTypeSizeInChars(Ptr.getType()));
Path.push_back(APValue::LValuePathEntry::ArrayIndex(Index));
Ptr = Ptr.getArray();
} else {
// TODO: figure out if base is virtual
Expand All @@ -170,12 +188,21 @@ APValue Pointer::toAPValue() const {
if (const auto *BaseOrMember = Desc->asDecl()) {
Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual}));
Ptr = Ptr.getBase();

if (const auto *FD = dyn_cast<FieldDecl>(BaseOrMember))
Offset += getFieldOffset(FD);

continue;
}
llvm_unreachable("Invalid field type");
}
}

// FIXME(perf): We compute the lvalue path above, but we can't supply it
// for dummy pointers (that causes crashes later in CheckConstantExpression).
if (isDummy())
Path.clear();

// We assemble the LValuePath starting from the innermost pointer to the
// outermost one. SO in a.b.c, the first element in Path will refer to
// the field 'c', while later code expects it to refer to 'a'.
Expand Down Expand Up @@ -220,13 +247,19 @@ std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const {
if (isIntegralPointer())
return (Twine("&(") + Twine(asIntPointer().Value + Offset) + ")").str();

return toAPValue().getAsString(Ctx, getType());
return toAPValue(Ctx).getAsString(Ctx, getType());
}

bool Pointer::isInitialized() const {
if (isIntegralPointer())
return true;

if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) {
const GlobalInlineDescriptor &GD =
*reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());
return GD.InitState == GlobalInitState::Initialized;
}

assert(PointeeStorage.BS.Pointee &&
"Cannot check if null pointer was initialized");
const Descriptor *Desc = getFieldDesc();
Expand All @@ -249,12 +282,6 @@ bool Pointer::isInitialized() const {
if (asBlockPointer().Base == 0)
return true;

if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) {
const GlobalInlineDescriptor &GD =
*reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());
return GD.InitState == GlobalInitState::Initialized;
}

// Field has its bit in an inline descriptor.
return getInlineDesc()->IsInitialized;
}
Expand All @@ -266,6 +293,13 @@ void Pointer::initialize() const {
assert(PointeeStorage.BS.Pointee && "Cannot initialize null pointer");
const Descriptor *Desc = getFieldDesc();

if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) {
GlobalInlineDescriptor &GD = *reinterpret_cast<GlobalInlineDescriptor *>(
asBlockPointer().Pointee->rawData());
GD.InitState = GlobalInitState::Initialized;
return;
}

assert(Desc);
if (Desc->isPrimitiveArray()) {
// Primitive global arrays don't have an initmap.
Expand Down Expand Up @@ -294,13 +328,6 @@ void Pointer::initialize() const {
return;
}

if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) {
GlobalInlineDescriptor &GD = *reinterpret_cast<GlobalInlineDescriptor *>(
asBlockPointer().Pointee->rawData());
GD.InitState = GlobalInitState::Initialized;
return;
}

// Field has its bit in an inline descriptor.
assert(PointeeStorage.BS.Base != 0 &&
"Only composite fields can be initialised");
Expand Down Expand Up @@ -344,10 +371,12 @@ bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {

std::optional<APValue> Pointer::toRValue(const Context &Ctx,
QualType ResultType) const {
const ASTContext &ASTCtx = Ctx.getASTContext();
assert(!ResultType.isNull());
// Method to recursively traverse composites.
std::function<bool(QualType, const Pointer &, APValue &)> Composite;
Composite = [&Composite, &Ctx](QualType Ty, const Pointer &Ptr, APValue &R) {
Composite = [&Composite, &Ctx, &ASTCtx](QualType Ty, const Pointer &Ptr,
APValue &R) {
if (const auto *AT = Ty->getAs<AtomicType>())
Ty = AT->getValueType();

Expand All @@ -358,7 +387,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,

// Primitive values.
if (std::optional<PrimType> T = Ctx.classify(Ty)) {
TYPE_SWITCH(*T, R = Ptr.deref<T>().toAPValue());
TYPE_SWITCH(*T, R = Ptr.deref<T>().toAPValue(ASTCtx));
return true;
}

Expand All @@ -375,7 +404,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
QualType FieldTy = F.Decl->getType();
if (FP.isActive()) {
if (std::optional<PrimType> T = Ctx.classify(FieldTy)) {
TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue());
TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx));
} else {
Ok &= Composite(FieldTy, FP, Value);
}
Expand All @@ -398,7 +427,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
APValue &Value = R.getStructField(I);

if (std::optional<PrimType> T = Ctx.classify(FieldTy)) {
TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue());
TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx));
} else {
Ok &= Composite(FieldTy, FP, Value);
}
Expand Down Expand Up @@ -436,7 +465,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
APValue &Slot = R.getArrayInitializedElt(I);
const Pointer &EP = Ptr.atIndex(I);
if (std::optional<PrimType> T = Ctx.classify(ElemTy)) {
TYPE_SWITCH(*T, Slot = EP.deref<T>().toAPValue());
TYPE_SWITCH(*T, Slot = EP.deref<T>().toAPValue(ASTCtx));
} else {
Ok &= Composite(ElemTy, EP.narrow(), Slot);
}
Expand Down Expand Up @@ -475,7 +504,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
Values.reserve(VT->getNumElements());
for (unsigned I = 0; I != VT->getNumElements(); ++I) {
TYPE_SWITCH(ElemT, {
Values.push_back(Ptr.atIndex(I).deref<T>().toAPValue());
Values.push_back(Ptr.atIndex(I).deref<T>().toAPValue(ASTCtx));
});
}

Expand All @@ -493,11 +522,11 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,

// We can return these as rvalues, but we can't deref() them.
if (isZero() || isIntegralPointer())
return toAPValue();
return toAPValue(ASTCtx);

// Just load primitive types.
if (std::optional<PrimType> T = Ctx.classify(ResultType)) {
TYPE_SWITCH(*T, return this->deref<T>().toAPValue());
TYPE_SWITCH(*T, return this->deref<T>().toAPValue(ASTCtx));
}

// Return the composite type.
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/Pointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ class Pointer {
bool operator!=(const Pointer &P) const { return !(P == *this); }

/// Converts the pointer to an APValue.
APValue toAPValue() const;
APValue toAPValue(const ASTContext &ASTCtx) const;

/// Converts the pointer to a string usable in diagnostics.
std::string toDiagnosticString(const ASTContext &Ctx) const;
Expand Down
21 changes: 15 additions & 6 deletions clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -524,12 +524,21 @@ void Environment::initialize() {
assert(VarDecl != nullptr);
setStorageLocation(*VarDecl, createObject(*VarDecl, nullptr));
} else if (Capture.capturesThis()) {
const auto *SurroundingMethodDecl =
cast<CXXMethodDecl>(InitialTargetFunc->getNonClosureAncestor());
QualType ThisPointeeType =
SurroundingMethodDecl->getFunctionObjectParameterType();
setThisPointeeStorageLocation(
cast<RecordStorageLocation>(createObject(ThisPointeeType)));
if (auto *Ancestor = InitialTargetFunc->getNonClosureAncestor()) {
const auto *SurroundingMethodDecl = cast<CXXMethodDecl>(Ancestor);
QualType ThisPointeeType =
SurroundingMethodDecl->getFunctionObjectParameterType();
setThisPointeeStorageLocation(
cast<RecordStorageLocation>(createObject(ThisPointeeType)));
} else if (auto *FieldBeingInitialized =
dyn_cast<FieldDecl>(Parent->getLambdaContextDecl())) {
// This is in a field initializer, rather than a method.
setThisPointeeStorageLocation(
cast<RecordStorageLocation>(createObject(QualType(
FieldBeingInitialized->getParent()->getTypeForDecl(), 0))));
} else {
assert(false && "Unexpected this-capturing lambda context.");
}
}
}
} else if (MethodDecl->isImplicitObjectMemberFunction()) {
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/CodeGen/CGExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -814,8 +814,7 @@ bool ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD,
llvm::Constant *VTableAddressPoint =
CGM.getCXXABI().getVTableAddressPoint(BaseSubobject(CD, Offset),
VTableClass);
if (auto Authentication =
CGM.getVTablePointerAuthentication(VTableClass)) {
if (auto Authentication = CGM.getVTablePointerAuthentication(CD)) {
VTableAddressPoint = Emitter.tryEmitConstantSignedPointer(
VTableAddressPoint, *Authentication);
if (!VTableAddressPoint)
Expand Down
60 changes: 32 additions & 28 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1077,33 +1077,6 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
if (JA.isOffloading(Action::OFK_HIP))
getToolChain().AddHIPIncludeArgs(Args, CmdArgs);

// If we are compiling for a GPU target we want to override the system headers
// with ones created by the 'libc' project if present.
if (!Args.hasArg(options::OPT_nostdinc) &&
!Args.hasArg(options::OPT_nogpuinc) &&
!Args.hasArg(options::OPT_nobuiltininc)) {
// Without an offloading language we will include these headers directly.
// Offloading languages will instead only use the declarations stored in
// the resource directory at clang/lib/Headers/llvm_libc_wrappers.
if ((getToolChain().getTriple().isNVPTX() ||
getToolChain().getTriple().isAMDGCN()) &&
C.getActiveOffloadKinds() == Action::OFK_None) {
SmallString<128> P(llvm::sys::path::parent_path(D.Dir));
llvm::sys::path::append(P, "include");
llvm::sys::path::append(P, getToolChain().getTripleString());
CmdArgs.push_back("-internal-isystem");
CmdArgs.push_back(Args.MakeArgString(P));
} else if (C.getActiveOffloadKinds() == Action::OFK_OpenMP) {
// TODO: CUDA / HIP include their own headers for some common functions
// implemented here. We'll need to clean those up so they do not conflict.
SmallString<128> P(D.ResourceDir);
llvm::sys::path::append(P, "include");
llvm::sys::path::append(P, "llvm_libc_wrappers");
CmdArgs.push_back("-internal-isystem");
CmdArgs.push_back(Args.MakeArgString(P));
}
}

// If we are offloading to a target via OpenMP we need to include the
// openmp_wrappers folder which contains alternative system headers.
if (JA.isDeviceOffloading(Action::OFK_OpenMP) &&
Expand Down Expand Up @@ -1276,6 +1249,35 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
});
}

// If we are compiling for a GPU target we want to override the system headers
// with ones created by the 'libc' project if present.
// TODO: This should be moved to `AddClangSystemIncludeArgs` by passing the
// OffloadKind as an argument.
if (!Args.hasArg(options::OPT_nostdinc) &&
!Args.hasArg(options::OPT_nogpuinc) &&
!Args.hasArg(options::OPT_nobuiltininc)) {
// Without an offloading language we will include these headers directly.
// Offloading languages will instead only use the declarations stored in
// the resource directory at clang/lib/Headers/llvm_libc_wrappers.
if ((getToolChain().getTriple().isNVPTX() ||
getToolChain().getTriple().isAMDGCN()) &&
C.getActiveOffloadKinds() == Action::OFK_None) {
SmallString<128> P(llvm::sys::path::parent_path(D.Dir));
llvm::sys::path::append(P, "include");
llvm::sys::path::append(P, getToolChain().getTripleString());
CmdArgs.push_back("-internal-isystem");
CmdArgs.push_back(Args.MakeArgString(P));
} else if (C.getActiveOffloadKinds() == Action::OFK_OpenMP) {
// TODO: CUDA / HIP include their own headers for some common functions
// implemented here. We'll need to clean those up so they do not conflict.
SmallString<128> P(D.ResourceDir);
llvm::sys::path::append(P, "include");
llvm::sys::path::append(P, "llvm_libc_wrappers");
CmdArgs.push_back("-internal-isystem");
CmdArgs.push_back(Args.MakeArgString(P));
}
}

// Add system include arguments for all targets but IAMCU.
if (!IsIAMCU)
forAllAssociatedToolChains(C, JA, getToolChain(),
Expand Down Expand Up @@ -6664,7 +6666,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
StringRef S0 = A->getValue(), S = S0;
unsigned Size, Offset = 0;
if (!Triple.isAArch64() && !Triple.isLoongArch() && !Triple.isRISCV() &&
!Triple.isX86())
!Triple.isX86() &&
!(!Triple.isOSAIX() && (Triple.getArch() == llvm::Triple::ppc ||
Triple.getArch() == llvm::Triple::ppc64)))
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getAsString(Args) << TripleStr;
else if (S.consumeInteger(10, Size) ||
Expand Down
29 changes: 20 additions & 9 deletions clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -372,10 +372,6 @@ class AnnotatingParser {
OpeningParen.Previous->is(tok::kw__Generic)) {
Contexts.back().ContextType = Context::C11GenericSelection;
Contexts.back().IsExpression = true;
} else if (Line.InPPDirective &&
(!OpeningParen.Previous ||
OpeningParen.Previous->isNot(tok::identifier))) {
Contexts.back().IsExpression = true;
} else if (Contexts[Contexts.size() - 2].CaretFound) {
// This is the parameter list of an ObjC block.
Contexts.back().IsExpression = false;
Expand All @@ -388,7 +384,20 @@ class AnnotatingParser {
OpeningParen.Previous->MatchingParen->isOneOf(
TT_ObjCBlockLParen, TT_FunctionTypeLParen)) {
Contexts.back().IsExpression = false;
} else if (!Line.MustBeDeclaration && !Line.InPPDirective) {
} else if (Line.InPPDirective) {
auto IsExpr = [&OpeningParen] {
const auto *Tok = OpeningParen.Previous;
if (!Tok || Tok->isNot(tok::identifier))
return true;
Tok = Tok->Previous;
while (Tok && Tok->endsSequence(tok::coloncolon, tok::identifier)) {
assert(Tok->Previous);
Tok = Tok->Previous->Previous;
}
return !Tok || !Tok->Tok.getIdentifierInfo();
};
Contexts.back().IsExpression = IsExpr();
} else if (!Line.MustBeDeclaration) {
bool IsForOrCatch =
OpeningParen.Previous &&
OpeningParen.Previous->isOneOf(tok::kw_for, tok::kw_catch);
Expand Down Expand Up @@ -2458,9 +2467,9 @@ class AnnotatingParser {
Current.setType(TT_CastRParen);
if (Current.MatchingParen && Current.Next &&
!Current.Next->isBinaryOperator() &&
!Current.Next->isOneOf(tok::semi, tok::colon, tok::l_brace,
tok::comma, tok::period, tok::arrow,
tok::coloncolon, tok::kw_noexcept)) {
!Current.Next->isOneOf(
tok::semi, tok::colon, tok::l_brace, tok::l_paren, tok::comma,
tok::period, tok::arrow, tok::coloncolon, tok::kw_noexcept)) {
if (FormatToken *AfterParen = Current.MatchingParen->Next;
AfterParen && AfterParen->isNot(tok::caret)) {
// Make sure this isn't the return type of an Obj-C block declaration.
Expand Down Expand Up @@ -2616,8 +2625,10 @@ class AnnotatingParser {
return false;

// int a or auto a.
if (PreviousNotConst->isOneOf(tok::identifier, tok::kw_auto))
if (PreviousNotConst->isOneOf(tok::identifier, tok::kw_auto) &&
PreviousNotConst->isNot(TT_StatementAttributeLikeMacro)) {
return true;
}

// *a or &a or &&a.
if (PreviousNotConst->is(TT_PointerOrReference))
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Headers/prfchwintrin.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*/

#if !defined(__X86INTRIN_H) && !defined(_MM3DNOW_H_INCLUDED)
#error "Never use <prfchwintrin.h> directly; include <x86intrin.h> or <mm3dnow.h> instead."
#error "Never use <prfchwintrin.h> directly; include <x86intrin.h> instead."
#endif

#ifndef __PRFCHWINTRIN_H
Expand Down
10 changes: 9 additions & 1 deletion clang/lib/Parse/ParseAST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,15 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) {
bool HaveLexer = S.getPreprocessor().getCurrentLexer();

if (HaveLexer) {
llvm::TimeTraceScope TimeScope("Frontend");
llvm::TimeTraceScope TimeScope("Frontend", [&]() {
llvm::TimeTraceMetadata M;
if (llvm::isTimeTraceVerbose()) {
const SourceManager &SM = S.getSourceManager();
if (const auto *FE = SM.getFileEntryForID(SM.getMainFileID()))
M.File = FE->tryGetRealPathName();
}
return M;
});
P.Initialize();
Parser::DeclGroupPtrTy ADecl;
Sema::ModuleImportState ImportState;
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Parse/ParseExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3597,7 +3597,7 @@ void Parser::injectEmbedTokens() {
I += 2;
}
PP.EnterTokenStream(std::move(Toks), /*DisableMacroExpansion=*/true,
/*IsReinject=*/false);
/*IsReinject=*/true);
ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
}

Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Sema/SemaAvailability.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,12 @@ ShouldDiagnoseAvailabilityOfDecl(Sema &S, const NamedDecl *D,
break;
}

// For alias templates, get the underlying declaration.
if (const auto *ADecl = dyn_cast<TypeAliasTemplateDecl>(D)) {
D = ADecl->getTemplatedDecl();
Result = D->getAvailability(Message);
}

// Forward class declarations get their attributes from their definition.
if (const auto *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) {
if (IDecl->getDefinition()) {
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5247,6 +5247,10 @@ static void handleXRayLogArgsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {

static void handlePatchableFunctionEntryAttr(Sema &S, Decl *D,
const ParsedAttr &AL) {
if (S.Context.getTargetInfo().getTriple().isOSAIX()) {
S.Diag(AL.getLoc(), diag::err_aix_attr_unsupported) << AL;
return;
}
uint32_t Count = 0, Offset = 0;
if (!S.checkUInt32Argument(AL, AL.getArgAsExpr(0), Count, 0, true))
return;
Expand Down
25 changes: 8 additions & 17 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14117,7 +14117,14 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) {
// Okay: we can take the address of a field.
// Could be a pointer to member, though, if there is an explicit
// scope qualifier for the class.
if (isa<DeclRefExpr>(op) && cast<DeclRefExpr>(op)->getQualifier()) {

// [C++26] [expr.prim.id.general]
// If an id-expression E denotes a non-static non-type member
// of some class C [...] and if E is a qualified-id, E is
// not the un-parenthesized operand of the unary & operator [...]
// the id-expression is transformed into a class member access expression.
if (isa<DeclRefExpr>(op) && cast<DeclRefExpr>(op)->getQualifier() &&
!isa<ParenExpr>(OrigOp.get())) {
DeclContext *Ctx = dcl->getDeclContext();
if (Ctx && Ctx->isRecord()) {
if (dcl->getType()->isReferenceType()) {
Expand All @@ -14127,22 +14134,6 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) {
return QualType();
}

// C++11 [expr.unary.op] p4:
// A pointer to member is only formed when an explicit & is used and
// its operand is a qualified-id not enclosed in parentheses.
if (isa<ParenExpr>(OrigOp.get())) {
SourceLocation LeftParenLoc = OrigOp.get()->getBeginLoc(),
RightParenLoc = OrigOp.get()->getEndLoc();

Diag(LeftParenLoc,
diag::err_form_ptr_to_member_from_parenthesized_expr)
<< SourceRange(OpLoc, RightParenLoc)
<< FixItHint::CreateRemoval(LeftParenLoc)
<< FixItHint::CreateRemoval(RightParenLoc);

// Continuing might lead to better error recovery.
}

while (cast<RecordDecl>(Ctx)->isAnonymousStructOrUnion())
Ctx = Ctx->getParent();

Expand Down
12 changes: 6 additions & 6 deletions clang/lib/Sema/SemaOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6168,14 +6168,14 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective(
DMC->getDefaultmapModifierLoc();
}
for (unsigned VC = 0; VC < DefaultmapKindNum; ++VC) {
auto Kind = static_cast<OpenMPDefaultmapClauseKind>(VC);
auto K = static_cast<OpenMPDefaultmapClauseKind>(VC);
for (unsigned I = 0; I < OMPC_MAP_delete; ++I) {
ArrayRef<Expr *> ImplicitMap = DSAChecker.getImplicitMap(
Kind, static_cast<OpenMPMapClauseKind>(I));
ArrayRef<Expr *> ImplicitMap =
DSAChecker.getImplicitMap(K, static_cast<OpenMPMapClauseKind>(I));
ImplicitMaps[VC][I].append(ImplicitMap.begin(), ImplicitMap.end());
}
ArrayRef<OpenMPMapModifierKind> ImplicitModifier =
DSAChecker.getImplicitMapModifier(Kind);
DSAChecker.getImplicitMapModifier(K);
ImplicitMapModifiers[VC].append(ImplicitModifier.begin(),
ImplicitModifier.end());
std::fill_n(std::back_inserter(ImplicitMapModifiersLoc[VC]),
Expand Down Expand Up @@ -6249,10 +6249,10 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective(
continue;
CXXScopeSpec MapperIdScopeSpec;
DeclarationNameInfo MapperId;
auto Kind = static_cast<OpenMPMapClauseKind>(ClauseKindCnt);
auto K = static_cast<OpenMPMapClauseKind>(ClauseKindCnt);
if (OMPClause *Implicit = ActOnOpenMPMapClause(
nullptr, ImplicitMapModifiers[I], ImplicitMapModifiersLoc[I],
MapperIdScopeSpec, MapperId, Kind, /*IsMapTypeImplicit=*/true,
MapperIdScopeSpec, MapperId, K, /*IsMapTypeImplicit=*/true,
SourceLocation(), SourceLocation(), ImplicitMap,
OMPVarListLocTy())) {
ClausesWithImplicit.emplace_back(Implicit);
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3344,6 +3344,10 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
*this, /*PointOfInstantiation=*/TemplateLoc,
/*Entity=*/AliasTemplate,
/*TemplateArgs=*/TemplateArgLists.getInnermost());

// Diagnose uses of this alias.
(void)DiagnoseUseOfDecl(AliasTemplate, TemplateLoc);

if (Inst.isInvalid())
return QualType();

Expand Down
25 changes: 11 additions & 14 deletions clang/lib/Sema/SemaTemplateDeductionGuide.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -363,8 +363,7 @@ struct ConvertConstructorToDeductionGuideTransform {
return nullptr;
// Constraints require that we substitute depth-1 arguments
// to match depths when substituted for evaluation later
Depth1Args.push_back(SemaRef.Context.getCanonicalTemplateArgument(
SemaRef.Context.getInjectedTemplateArg(NewParam)));
Depth1Args.push_back(SemaRef.Context.getInjectedTemplateArg(NewParam));

if (NestedPattern) {
TemplateDeclInstantiator Instantiator(SemaRef, DC,
Expand All @@ -379,8 +378,7 @@ struct ConvertConstructorToDeductionGuideTransform {
"Unexpected template parameter depth");

AllParams.push_back(NewParam);
SubstArgs.push_back(SemaRef.Context.getCanonicalTemplateArgument(
SemaRef.Context.getInjectedTemplateArg(NewParam)));
SubstArgs.push_back(SemaRef.Context.getInjectedTemplateArg(NewParam));
}

// Substitute new template parameters into requires-clause if present.
Expand Down Expand Up @@ -795,8 +793,8 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
/*NewIndex=*/AdjustedAliasTemplateArgs.size(),
getTemplateParameterDepth(TP) + AdjustDepth);

auto NewTemplateArgument = Context.getCanonicalTemplateArgument(
Context.getInjectedTemplateArg(NewParam));
TemplateArgument NewTemplateArgument =
Context.getInjectedTemplateArg(NewParam);
AdjustedAliasTemplateArgs.push_back(NewTemplateArgument);
}
// Template arguments used to transform the template arguments in
Expand All @@ -822,8 +820,8 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
getTemplateParameterDepth(TP) + AdjustDepth);
FirstUndeducedParamIdx += 1;
assert(TemplateArgsForBuildingRC[Index].isNull());
TemplateArgsForBuildingRC[Index] = Context.getCanonicalTemplateArgument(
Context.getInjectedTemplateArg(NewParam));
TemplateArgsForBuildingRC[Index] =
Context.getInjectedTemplateArg(NewParam);
continue;
}
TemplateArgumentLoc Input =
Expand Down Expand Up @@ -923,8 +921,8 @@ Expr *buildIsDeducibleConstraint(Sema &SemaRef,
/*NewIndex=*/TransformedTemplateArgs.size(),
getTemplateParameterDepth(TP) + AdjustDepth);

auto NewTemplateArgument = Context.getCanonicalTemplateArgument(
Context.getInjectedTemplateArg(NewParam));
TemplateArgument NewTemplateArgument =
Context.getInjectedTemplateArg(NewParam);
TransformedTemplateArgs.push_back(NewTemplateArgument);
}
// Transformed the ReturnType to restore the uninstantiated depth.
Expand Down Expand Up @@ -1087,8 +1085,8 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
getTemplateParameterDepth(TP));
FPrimeTemplateParams.push_back(NewParam);

auto NewTemplateArgument = Context.getCanonicalTemplateArgument(
Context.getInjectedTemplateArg(NewParam));
TemplateArgument NewTemplateArgument =
Context.getInjectedTemplateArg(NewParam);
TransformedDeducedAliasArgs[AliasTemplateParamIdx] = NewTemplateArgument;
}
unsigned FirstUndeducedParamIdx = FPrimeTemplateParams.size();
Expand All @@ -1109,8 +1107,7 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
assert(TemplateArgsForBuildingFPrime[FTemplateParamIdx].isNull() &&
"The argument must be null before setting");
TemplateArgsForBuildingFPrime[FTemplateParamIdx] =
Context.getCanonicalTemplateArgument(
Context.getInjectedTemplateArg(NewParam));
Context.getInjectedTemplateArg(NewParam);
}

// To form a deduction guide f' from f, we leverage clang's instantiation
Expand Down
18 changes: 9 additions & 9 deletions clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -373,14 +373,14 @@ static std::optional<int64_t> getConcreteValue(std::optional<NonLoc> SV) {
}

static Messages getPrecedesMsgs(const SubRegion *Region, NonLoc Offset) {
std::string RegName = getRegionName(Region);
SmallString<128> Buf;
llvm::raw_svector_ostream Out(Buf);
Out << "Access of " << RegName << " at negative byte offset";
if (auto ConcreteIdx = Offset.getAs<nonloc::ConcreteInt>())
Out << ' ' << ConcreteIdx->getValue();
return {formatv("Out of bound access to memory preceding {0}", RegName),
std::string(Buf)};
std::string RegName = getRegionName(Region), OffsetStr = "";

if (auto ConcreteOffset = getConcreteValue(Offset))
OffsetStr = formatv(" {0}", ConcreteOffset);

return {
formatv("Out of bound access to memory preceding {0}", RegName),
formatv("Access of {0} at negative byte offset{1}", RegName, OffsetStr)};
}

/// Try to divide `Val1` and `Val2` (in place) by `Divisor` and return true if
Expand Down Expand Up @@ -609,7 +609,7 @@ void ArrayBoundCheckerV2::performCheck(const Expr *E, CheckerContext &C) const {
// CHECK UPPER BOUND
DefinedOrUnknownSVal Size = getDynamicExtent(State, Reg, SVB);
if (auto KnownSize = Size.getAs<NonLoc>()) {
// In a situation where both overflow and overflow are possible (but the
// In a situation where both underflow and overflow are possible (but the
// index is either tainted or known to be invalid), the logic of this
// checker will first assume that the offset is non-negative, and then
// (with this additional assumption) it will detect an overflow error.
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/StaticAnalyzer/Core/BugReporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2198,7 +2198,7 @@ const Decl *PathSensitiveBugReport::getDeclWithIssue() const {
void BasicBugReport::Profile(llvm::FoldingSetNodeID& hash) const {
hash.AddInteger(static_cast<int>(getKind()));
hash.AddPointer(&BT);
hash.AddString(Description);
hash.AddString(getShortDescription());
assert(Location.isValid());
Location.Profile(hash);

Expand All @@ -2213,7 +2213,7 @@ void BasicBugReport::Profile(llvm::FoldingSetNodeID& hash) const {
void PathSensitiveBugReport::Profile(llvm::FoldingSetNodeID &hash) const {
hash.AddInteger(static_cast<int>(getKind()));
hash.AddPointer(&BT);
hash.AddString(Description);
hash.AddString(getShortDescription());
PathDiagnosticLocation UL = getUniqueingLocation();
if (UL.isValid()) {
UL.Profile(hash);
Expand Down
20 changes: 20 additions & 0 deletions clang/test/AST/Interp/codegen.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -o - %s -fexperimental-new-constant-interpreter | FileCheck %s


int arr[2];
// CHECK: @pastEnd = constant ptr getelementptr (i8, ptr @arr, i64 8)
int &pastEnd = arr[2];

// CHECK: @F = constant ptr @arr, align 8
int &F = arr[0];

struct S {
int a;
float c[3];
};

// CHECK: @s = global %struct.S zeroinitializer, align 4
S s;
// CHECK: @sp = constant ptr getelementptr (i8, ptr @s, i64 16), align 8
float &sp = s.c[3];
8 changes: 8 additions & 0 deletions clang/test/AST/Interp/cxx11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,11 @@ void A::f(SortOrder order) {
return;
}
}

namespace FinalLtorDiags {
template<int*> struct A {}; // both-note {{template parameter is declared here}}
int k;
int *q = &k; // both-note {{declared here}}
A<q> c; // both-error {{non-type template argument of type 'int *' is not a constant expression}} \
// both-note {{read of non-constexpr variable 'q' is not allowed in a constant expression}}
}
5 changes: 5 additions & 0 deletions clang/test/AST/Interp/new-delete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -560,4 +560,9 @@ constexpr int a() { // both-error {{never produces a constant expression}}
}
static_assert(a() == 1, ""); // both-error {{not an integral constant expression}} \
// both-note {{in call to 'a()'}}


static_assert(true ? *new int : 4, ""); // both-error {{expression is not an integral constant expression}} \
// both-note {{read of uninitialized object is not allowed in a constant expression}}

#endif
34 changes: 18 additions & 16 deletions clang/test/AST/ast-dump-ctad-alias.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,24 @@ Out2<double>::AInner t(1.0);
// CHECK-NEXT: | | |-UnresolvedLookupExpr {{.*}} '<dependent type>' lvalue (no ADL) = 'Concept'
// CHECK-NEXT: | | | |-TemplateArgument type 'int'
// CHECK-NEXT: | | | | `-BuiltinType {{.*}} 'int'
// CHECK-NEXT: | | | `-TemplateArgument type 'type-parameter-1-0'
// CHECK-NEXT: | | | `-TemplateTypeParmType {{.*}} 'type-parameter-1-0' dependent depth 1 index 0
// CHECK-NEXT: | | | `-TemplateArgument type 'Y':'type-parameter-1-0'
// CHECK-NEXT: | | | `-TemplateTypeParmType {{.*}} 'Y' dependent depth 1 index 0
// CHECK-NEXT: | | | `-TemplateTypeParm {{.*}} 'Y'
// CHECK-NEXT: | | `-TypeTraitExpr {{.*}} 'bool' __is_deducible
// CHECK-NEXT: | | |-DeducedTemplateSpecializationType {{.*}} 'Out2<double>::AInner' dependent
// CHECK-NEXT: | | | `-name: 'Out2<double>::AInner'
// CHECK-NEXT: | | | `-TypeAliasTemplateDecl {{.+}} AInner{{$}}
// CHECK-NEXT: | | `-ElaboratedType {{.*}} 'Inner<type-parameter-1-0>' sugar dependent
// CHECK-NEXT: | | `-TemplateSpecializationType {{.*}} 'Inner<type-parameter-1-0>' dependent
// CHECK-NEXT: | | `-ElaboratedType {{.*}} 'Inner<Y>' sugar dependent
// CHECK-NEXT: | | `-TemplateSpecializationType {{.*}} 'Inner<Y>' dependent
// CHECK-NEXT: | | |-name: 'Inner':'Out<int>::Inner' qualified
// CHECK-NEXT: | | | `-ClassTemplateDecl {{.+}} Inner{{$}}
// CHECK-NEXT: | | `-TemplateArgument type 'type-parameter-1-0'
// CHECK-NEXT: | | `-SubstTemplateTypeParmType {{.*}} 'type-parameter-1-0'
// CHECK-NEXT: | | `-TemplateArgument type 'Y'
// CHECK-NEXT: | | `-SubstTemplateTypeParmType {{.*}} 'Y'
// CHECK-NEXT: | | |-FunctionTemplate {{.*}} '<deduction guide for Inner>'
// CHECK-NEXT: | | `-TemplateTypeParmType {{.*}} 'type-parameter-1-0' dependent depth 1 index 0
// CHECK-NEXT: | |-CXXDeductionGuideDecl {{.*}} <deduction guide for AInner> 'auto (type-parameter-0-0) -> Inner<type-parameter-0-0>'
// CHECK-NEXT: | | `-ParmVarDecl {{.*}} 'type-parameter-0-0'
// CHECK-NEXT: | | `-TemplateTypeParmType {{.*}} 'Y' dependent depth 1 index 0
// CHECK-NEXT: | | `-TemplateTypeParm {{.*}} 'Y'
// CHECK-NEXT: | |-CXXDeductionGuideDecl {{.*}} <deduction guide for AInner> 'auto (Y) -> Inner<Y>'
// CHECK-NEXT: | | `-ParmVarDecl {{.*}} 'Y'
// CHECK-NEXT: | `-CXXDeductionGuideDecl {{.*}} used <deduction guide for AInner> 'auto (double) -> Inner<double>' implicit_instantiation
// CHECK-NEXT: | |-TemplateArgument type 'double'
// CHECK-NEXT: | | `-BuiltinType {{.*}} 'double'
Expand Down Expand Up @@ -77,8 +79,8 @@ AFoo3 afoo3{0, 1};
// CHECK-NEXT: | |-UnresolvedLookupExpr {{.*}} '<dependent type>' lvalue (no ADL) = 'Concept'
// CHECK-NEXT: | | |-TemplateArgument type 'int'
// CHECK-NEXT: | | | `-BuiltinType {{.*}} 'int'
// CHECK-NEXT: | | `-TemplateArgument type 'type-parameter-0-1'
// CHECK-NEXT: | | `-TemplateTypeParmType {{.*}} 'type-parameter-0-1' dependent depth 0 index 1
// CHECK-NEXT: | | `-TemplateArgument type 'V'
// CHECK-NEXT: | | `-TemplateTypeParmType {{.*}} 'V' dependent depth 0 index 1

template <typename... T1>
struct Foo {
Expand All @@ -88,16 +90,16 @@ struct Foo {
template <typename...T2>
using AFoo = Foo<T2...>;
AFoo a(1, 2);
// CHECK: |-CXXDeductionGuideDecl {{.*}} implicit <deduction guide for AFoo> 'auto (type-parameter-0-0...) -> Foo<type-parameter-0-0...>'
// CHECK-NEXT: | | `-ParmVarDecl {{.*}} 'type-parameter-0-0...' pack
// CHECK: |-CXXDeductionGuideDecl {{.*}} implicit <deduction guide for AFoo> 'auto (T2...) -> Foo<T2...>'
// CHECK-NEXT: | | `-ParmVarDecl {{.*}} 'T2...' pack
// CHECK-NEXT: | `-CXXDeductionGuideDecl {{.*}} implicit used <deduction guide for AFoo> 'auto (int, int) -> Foo<int, int>' implicit_instantiation

template <typename T>
using BFoo = Foo<T, T>;
BFoo b2(1.0, 2.0);
// CHECK: |-CXXDeductionGuideDecl {{.*}} implicit <deduction guide for BFoo> 'auto (type-parameter-0-0, type-parameter-0-0) -> Foo<type-parameter-0-0, type-parameter-0-0>'
// CHECK-NEXT: | | |-ParmVarDecl {{.*}} 'type-parameter-0-0'
// CHECK-NEXT: | | `-ParmVarDecl {{.*}} 'type-parameter-0-0'
// CHECK: |-CXXDeductionGuideDecl {{.*}} implicit <deduction guide for BFoo> 'auto (T, T) -> Foo<T, T>'
// CHECK-NEXT: | | |-ParmVarDecl {{.*}} 'T'
// CHECK-NEXT: | | `-ParmVarDecl {{.*}} 'T'
// CHECK-NEXT: | `-CXXDeductionGuideDecl {{.*}} implicit used <deduction guide for BFoo> 'auto (double, double) -> Foo<double, double>' implicit_instantiation

namespace GH90209 {
Expand Down
21 changes: 21 additions & 0 deletions clang/test/Analysis/out-of-bounds-diagnostics.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,27 @@ int underflowWithDeref(void) {
// expected-note@-2 {{Access of 'TenElements' at negative byte offset -4}}
}

int rng(void);
int getIndex(void) {
switch (rng()) {
case 1: return -152;
case 2: return -160;
case 3: return -168;
default: return -172;
}
}

void gh86959(void) {
// Previously code like this produced many almost-identical bug reports that
// only differed in the offset value. Verify that now we only see one report.

// expected-note@+1 {{Entering loop body}}
while (rng())
TenElements[getIndex()] = 10;
// expected-warning@-1 {{Out of bound access to memory preceding 'TenElements'}}
// expected-note@-2 {{Access of 'TenElements' at negative byte offset -688}}
}

int scanf(const char *restrict fmt, ...);

void taintedIndex(void) {
Expand Down
42 changes: 30 additions & 12 deletions clang/test/CXX/expr/expr.unary/expr.unary.op/p4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,36 @@ namespace test2 {
}

namespace GH40906 {
struct A {
int val;
void func() {}
};
struct S {
int x;
void func();
static_assert(__is_same_as(decltype((S::x)), int&), "");
static_assert(__is_same_as(decltype(&(S::x)), int*), "");

void test() {
decltype(&(A::val)) ptr1; // expected-error {{cannot form pointer to member from a parenthesized expression; did you mean to remove the parentheses?}}
int A::* ptr2 = &(A::val); // expected-error {{invalid use of non-static data member 'val'}}
// FIXME: provide better error messages
static_assert(__is_same_as(decltype((S::func)), int&), ""); // expected-error {{call to non-static member function without an object argument}}
static_assert(__is_same_as(decltype(&(S::func)), int*), ""); // expected-error {{call to non-static member function without an object argument}}
};
static_assert(__is_same_as(decltype((S::x)), int&), "");
static_assert(__is_same_as(decltype(&(S::x)), int*), "");
static_assert(__is_same_as(decltype((S::func)), int&), ""); // expected-error {{call to non-static member function without an object argument}}
static_assert(__is_same_as(decltype(&(S::func)), int*), ""); // expected-error {{call to non-static member function without an object argument}}

struct A { int x;};

char q(int *);
short q(int A::*);

template <typename T>
constexpr int f(char (*)[sizeof(q(&T::x))]) { return 1; }

template <typename T>
constexpr int f(char (*)[sizeof(q(&(T::x)))]) { return 2; }

constexpr int g(char (*p)[sizeof(char)] = 0) { return f<A>(p); }
constexpr int h(char (*p)[sizeof(short)] = 0) { return f<A>(p); }

static_assert(g() == 2);
static_assert(h() == 1);

// FIXME: Error messages in these cases are less than clear, we can do
// better.
int size = sizeof(&(A::func)); // expected-error {{call to non-static member function without an object argument}}
void (A::* ptr3)() = &(A::func); // expected-error {{call to non-static member function without an object argument}}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ namespace std_example {
template<class T> struct A { // expected-note {{candidate}} expected-note {{implicit deduction guide}}
template<class U>
A(T &&, U &&, int *); // expected-note {{[with T = int, U = int] not viable: expects an rvalue}} \
// expected-note {{implicit deduction guide declared as 'template <class T, class U> A(T &&, type-parameter-0-1 &&, int *) -> A<T>'}}
// expected-note {{implicit deduction guide declared as 'template <class T, class U> A(T &&, U &&, int *) -> A<T>'}}
A(T &&, int *); // expected-note {{requires 2}} \
// expected-note {{implicit deduction guide declared as 'template <class T> A(T &&, int *) -> A<T>'}}
};
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CodeGen/attr-target-x86.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ void __attribute__((target("avx10.1-512"))) avx10_1_512(void) {}
// CHECK: #4 = {{.*}}"target-cpu"="i686" "target-features"="+cmov,+cx8,+x87,-avx,-avx10.1-256,-avx10.1-512,-avx2,-avx512bf16,-avx512bitalg,-avx512bw,-avx512cd,-avx512dq,-avx512f,-avx512fp16,-avx512ifma,-avx512vbmi,-avx512vbmi2,-avx512vl,-avx512vnni,-avx512vp2intersect,-avx512vpopcntdq,-avxifma,-avxneconvert,-avxvnni,-avxvnniint16,-avxvnniint8,-f16c,-fma,-fma4,-sha512,-sm3,-sm4,-sse4.1,-sse4.2,-vaes,-vpclmulqdq,-xop" "tune-cpu"="i686"
// CHECK: #5 = {{.*}}"target-cpu"="ivybridge" "target-features"="+avx,+cmov,+crc32,+cx16,+cx8,+f16c,+fsgsbase,+fxsr,+mmx,+pclmul,+popcnt,+rdrnd,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt,-aes,-avx10.1-256,-avx10.1-512,-vaes"
// CHECK-NOT: tune-cpu
// CHECK: #6 = {{.*}}"target-cpu"="i686" "target-features"="+cmov,+cx8,+x87,-3dnow,-3dnowa,-mmx"
// CHECK: #6 = {{.*}}"target-cpu"="i686" "target-features"="+cmov,+cx8,+x87,-mmx"
// CHECK: #7 = {{.*}}"target-cpu"="lakemont" "target-features"="+cx8,+mmx"
// CHECK-NOT: tune-cpu
// CHECK: #8 = {{.*}}"target-cpu"="i686" "target-features"="+cmov,+cx8,+x87" "tune-cpu"="sandybridge"
Expand Down
234 changes: 234 additions & 0 deletions clang/test/CodeGenCXX/ptrauth-global-constant-initializers.cpp

Large diffs are not rendered by default.

9 changes: 7 additions & 2 deletions clang/test/Driver/fpatchable-function-entry.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,20 @@
// RUN: %clang --target=loongarch64 %s -fpatchable-function-entry=1,0 -c -### 2>&1 | FileCheck %s
// RUN: %clang --target=riscv32 %s -fpatchable-function-entry=1,0 -c -### 2>&1 | FileCheck %s
// RUN: %clang --target=riscv64 %s -fpatchable-function-entry=1,0 -c -### 2>&1 | FileCheck %s
// RUN: %clang --target=powerpc-unknown-linux-gnu %s -fpatchable-function-entry=1,0 -c -### 2>&1 | FileCheck %s
// RUN: %clang --target=powerpc64-unknown-linux-gnu %s -fpatchable-function-entry=1,0 -c -### 2>&1 | FileCheck %s
// CHECK: "-fpatchable-function-entry=1"

// RUN: %clang --target=aarch64 -fsyntax-only %s -fpatchable-function-entry=1,1 -c -### 2>&1 | FileCheck --check-prefix=11 %s
// 11: "-fpatchable-function-entry=1" "-fpatchable-function-entry-offset=1"
// RUN: %clang --target=aarch64 -fsyntax-only %s -fpatchable-function-entry=2,1 -c -### 2>&1 | FileCheck --check-prefix=21 %s
// 21: "-fpatchable-function-entry=2" "-fpatchable-function-entry-offset=1"

// RUN: not %clang --target=ppc64 -fsyntax-only %s -fpatchable-function-entry=1 2>&1 | FileCheck --check-prefix=TARGET %s
// TARGET: error: unsupported option '-fpatchable-function-entry=1' for target 'ppc64'
// RUN: not %clang --target=powerpc64-ibm-aix-xcoff -fsyntax-only %s -fpatchable-function-entry=1 2>&1 | FileCheck --check-prefix=AIX64 %s
// AIX64: error: unsupported option '-fpatchable-function-entry=1' for target 'powerpc64-ibm-aix-xcoff'

// RUN: not %clang --target=powerpc-ibm-aix-xcoff -fsyntax-only %s -fpatchable-function-entry=1 2>&1 | FileCheck --check-prefix=AIX32 %s
// AIX32: error: unsupported option '-fpatchable-function-entry=1' for target 'powerpc-ibm-aix-xcoff'

// RUN: not %clang --target=x86_64 -fsyntax-only %s -fpatchable-function-entry=1,0, 2>&1 | FileCheck --check-prefix=EXCESS %s
// EXCESS: error: invalid argument '1,0,' to -fpatchable-function-entry=
Expand Down
8 changes: 4 additions & 4 deletions clang/test/Driver/gpu-libc-headers.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fopenmp=libomp --sysroot=./ \
// RUN: -fopenmp-targets=nvptx64-nvidia-cuda -Xopenmp-target=nvptx64-nvidia-cuda --offload-arch=sm_70 \
// RUN: -nogpulib %s 2>&1 | FileCheck %s --check-prefix=CHECK-HEADERS
// CHECK-HEADERS: "-cc1"{{.*}}"-internal-isystem" "{{.*}}include{{.*}}llvm_libc_wrappers"{{.*}}"-isysroot" "./"
// CHECK-HEADERS: "-cc1"{{.*}}"-internal-isystem" "{{.*}}include{{.*}}llvm_libc_wrappers"{{.*}}"-isysroot" "./"
// CHECK-HEADERS: "-cc1"{{.*}}"-isysroot" "./"{{.*}}"-internal-isystem" "{{.*}}include{{.*}}llvm_libc_wrappers"
// CHECK-HEADERS: "-cc1"{{.*}}"-isysroot" "./"{{.*}}"-internal-isystem" "{{.*}}include{{.*}}llvm_libc_wrappers"

// RUN: %clang -### --target=amdgcn-amd-amdhsa -mcpu=gfx90a --sysroot=./ \
// RUN: -nogpulib %s 2>&1 | FileCheck %s --check-prefix=CHECK-HEADERS-AMDGPU
// RUN: %clang -### --target=nvptx64-nvidia-cuda -march=sm_89 --sysroot=./ \
// RUN: -nogpulib %s 2>&1 | FileCheck %s --check-prefix=CHECK-HEADERS-NVPTX
// CHECK-HEADERS-AMDGPU: "-cc1"{{.*}}"-internal-isystem" "{{.*}}include{{.*}}amdgcn-amd-amdhsa"{{.*}}"-isysroot" "./"
// CHECK-HEADERS-NVPTX: "-cc1"{{.*}}"-internal-isystem" "{{.*}}include{{.*}}nvptx64-nvidia-cuda"{{.*}}"-isysroot" "./"
// CHECK-HEADERS-AMDGPU: "-cc1"{{.*}}"-isysroot" "./"{{.*}}"-internal-isystem" "{{.*}}include{{.*}}amdgcn-amd-amdhsa"
// CHECK-HEADERS-NVPTX: "-cc1"{{.*}}"-isysroot" "./"{{.*}}"-internal-isystem" "{{.*}}include{{.*}}nvptx64-nvidia-cuda"

// RUN: %clang -### --target=amdgcn-amd-amdhsa -mcpu=gfx1030 -nogpulib \
// RUN: -nogpuinc %s 2>&1 | FileCheck %s --check-prefix=CHECK-HEADERS-DISABLED
Expand Down
8 changes: 8 additions & 0 deletions clang/test/Preprocessor/embed_weird.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,14 @@ void f1() {
}
#endif

static_assert(_Generic(
#embed __FILE__ limit(1)
, int : 1, default : 0));

static_assert(alignof(typeof(
#embed __FILE__ limit(1)
)) == alignof(int));

struct HasChar {
signed char ch;
};
Expand Down
36 changes: 36 additions & 0 deletions clang/test/Sema/aarch64-neon-without-target-feature.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +dotprod -target-feature +fullfp16 -target-feature +fp16fml -target-feature +i8mm -target-feature +bf16 -verify -emit-llvm -o - %s

// REQUIRES: aarch64-registered-target

// This test is testing the diagnostics that Clang emits when compiling without '+neon'.

#include <arm_neon.h>

void undefined(uint32x2_t v2i32, uint32x4_t v4i32, uint16x8_t v8i16, uint8x16_t v16i8, uint8x8_t v8i8, float32x2_t v2f32, float32x4_t v4f32, float16x4_t v4f16, float64x2_t v2f64, bfloat16x4_t v4bf16, __bf16 bf16, poly64_t poly64, poly64x2_t poly64x2) {
// dotprod
vdot_u32(v2i32, v8i8, v8i8); // expected-error {{always_inline function 'vdot_u32' requires target feature 'neon'}}
vdot_laneq_u32(v2i32, v8i8, v16i8, 1); // expected-error {{always_inline function 'vdot_u32' requires target feature 'neon'}} expected-error {{'__builtin_neon_splat_laneq_v' needs target feature neon}}
// fp16
vceqz_f16(v4f16); // expected-error {{always_inline function 'vceqz_f16' requires target feature 'neon'}}
vrnd_f16(v4f16); // expected-error {{always_inline function 'vrnd_f16' requires target feature 'neon'}}
vmaxnm_f16(v4f16, v4f16); // expected-error {{always_inline function 'vmaxnm_f16' requires target feature 'neon'}}
vrndi_f16(v4f16); // expected-error {{always_inline function 'vrndi_f16' requires target feature 'neon'}}
// fp16fml depends on fp-armv8
vfmlal_low_f16(v2f32, v4f16, v4f16); // expected-error {{always_inline function 'vfmlal_low_f16' requires target feature 'neon'}}
// i8mm
vmmlaq_s32(v4i32, v8i16, v8i16); // expected-error {{always_inline function 'vmmlaq_s32' requires target feature 'neon'}}
vusdot_laneq_s32(v2i32, v8i8, v8i16, 0); // expected-error {{always_inline function 'vusdot_s32' requires target feature 'neon'}} expected-error {{'__builtin_neon_splat_laneq_v' needs target feature neon}}
// bf16
vbfdot_f32(v2f32, v4bf16, v4bf16); // expected-error {{always_inline function 'vbfdot_f32' requires target feature 'neon'}}
vcreate_bf16(10);
vdup_lane_bf16(v4bf16, 2); // expected-error {{'__builtin_neon_splat_lane_bf16' needs target feature bf16,neon}}
vdup_n_bf16(bf16); // expected-error {{always_inline function 'vdup_n_bf16' requires target feature 'neon'}}
vld1_bf16(0); // expected-error {{'__builtin_neon_vld1_bf16' needs target feature bf16,neon}}
vcvt_f32_bf16(v4bf16); // expected-error {{always_inline function 'vcvt_f32_bf16' requires target feature 'neon'}}
vcvt_bf16_f32(v4f32); // expected-error {{always_inline function 'vcvt_bf16_f32' requires target feature 'neon'}}
vmull_p64(poly64, poly64); // expected-error {{always_inline function 'vmull_p64' requires target feature 'neon'}}
vmull_high_p64(poly64x2, poly64x2); // expected-error {{always_inline function 'vmull_high_p64' requires target feature 'neon'}}
vtrn1_s8(v8i8, v8i8); // expected-error {{always_inline function 'vtrn1_s8' requires target feature 'neon'}}
vqabsq_s16(v8i16); // expected-error {{always_inline function 'vqabsq_s16' requires target feature 'neon'}}
vbslq_s16(v8i16, v8i16, v8i16);// expected-error {{always_inline function 'vbslq_s16' requires target feature 'neon'}}
}
5 changes: 5 additions & 0 deletions clang/test/Sema/patchable-function-entry-attr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,14 @@
// RUN: %clang_cc1 -triple loongarch64 -fsyntax-only -verify=silence %s
// RUN: %clang_cc1 -triple riscv32 -fsyntax-only -verify=silence %s
// RUN: %clang_cc1 -triple riscv64 -fsyntax-only -verify=silence %s
// RUN: %clang_cc1 -triple powerpc-unknown-linux-gnu -fsyntax-only -verify=silence %s
// RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu -fsyntax-only -verify=silence %s
// RUN: %clang_cc1 -triple ppc64le -fsyntax-only -verify %s
// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -fsyntax-only -verify=AIX %s
// RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -fsyntax-only -verify=AIX %s

// silence-no-diagnostics

// AIX-error@+2 {{'patchable_function_entry' attribute is not yet supported on AIX}}
// expected-warning@+1 {{unknown attribute 'patchable_function_entry' ignored}}
[[gnu::patchable_function_entry(0)]] void f();
2 changes: 2 additions & 0 deletions clang/test/SemaCXX/builtin_vectorelements.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// RUN: %clang_cc1 -triple x86_64 -std=c++20 -fsyntax-only -verify -disable-llvm-passes %s
// RUN: %clang_cc1 -triple x86_64 -std=c++20 -fsyntax-only -verify -disable-llvm-passes -fexperimental-new-constant-interpreter %s

// REQUIRES: aarch64-registered-target
// RUN: %clang_cc1 -triple aarch64 -target-feature +sve -std=c++20 -fsyntax-only -verify -disable-llvm-passes %s
// RUN: %clang_cc1 -triple aarch64 -target-feature +sve -std=c++20 -fsyntax-only -verify -disable-llvm-passes -fexperimental-new-constant-interpreter %s

template <typename T>
using VecT __attribute__((vector_size(16))) = T;
Expand Down
30 changes: 15 additions & 15 deletions clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ struct Foo {

template <typename X, int Y>
using Bar = Foo<X, sizeof(X)>; // expected-note {{candidate template ignored: couldn't infer template argument 'X'}} \
// expected-note {{implicit deduction guide declared as 'template <typename X> requires __is_deducible(test9::Bar, Foo<type-parameter-0-0, sizeof(type-parameter-0-0)>) Bar(Foo<type-parameter-0-0, sizeof(type-parameter-0-0)>) -> Foo<type-parameter-0-0, sizeof(type-parameter-0-0)>'}} \
// expected-note {{implicit deduction guide declared as 'template <typename X> requires __is_deducible(test9::Bar, Foo<type-parameter-0-0, sizeof(type-parameter-0-0)>) Bar(const type-parameter-0-0 (&)[sizeof(type-parameter-0-0)]) -> Foo<type-parameter-0-0, sizeof(type-parameter-0-0)>'}} \
// expected-note {{implicit deduction guide declared as 'template <typename X> requires __is_deducible(test9::Bar, Foo<X, sizeof(X)>) Bar(Foo<X, sizeof(X)>) -> Foo<X, sizeof(X)>'}} \
// expected-note {{implicit deduction guide declared as 'template <typename X> requires __is_deducible(test9::Bar, Foo<X, sizeof(X)>) Bar(const X (&)[sizeof(X)]) -> Foo<X, sizeof(X)>'}} \
// expected-note {{candidate template ignored: constraints not satisfied [with X = int]}} \
// expected-note {{cannot deduce template arguments for 'Bar' from 'Foo<int, 4UL>'}}

Expand All @@ -138,13 +138,13 @@ namespace test11 {
struct A {};
template<class T> struct Foo { T c; };
template<class X, class Y=A>
using AFoo = Foo<Y>; // expected-note {{candidate template ignored: could not match 'Foo<type-parameter-0-0>' against 'int'}} \
// expected-note {{implicit deduction guide declared as 'template <class Y = A> requires __is_deducible(test11::AFoo, Foo<type-parameter-0-0>) AFoo(Foo<type-parameter-0-0>) -> Foo<type-parameter-0-0>'}} \
using AFoo = Foo<Y>; // expected-note {{candidate template ignored: could not match 'Foo<Y>' against 'int'}} \
// expected-note {{implicit deduction guide declared as 'template <class Y = A> requires __is_deducible(test11::AFoo, Foo<Y>) AFoo(Foo<Y>) -> Foo<Y>'}} \
// expected-note {{candidate template ignored: constraints not satisfied [with Y = int]}} \
// expected-note {{cannot deduce template arguments for 'AFoo' from 'Foo<int>'}} \
// expected-note {{implicit deduction guide declared as 'template <class Y = A> requires __is_deducible(test11::AFoo, Foo<type-parameter-0-0>) AFoo(type-parameter-0-0) -> Foo<type-parameter-0-0>'}} \
// expected-note {{implicit deduction guide declared as 'template <class Y = A> requires __is_deducible(test11::AFoo, Foo<Y>) AFoo(Y) -> Foo<Y>'}} \
// expected-note {{candidate function template not viable: requires 0 arguments, but 1 was provided}} \
// expected-note {{implicit deduction guide declared as 'template <class Y = A> requires __is_deducible(test11::AFoo, Foo<type-parameter-0-0>) AFoo() -> Foo<type-parameter-0-0>'}}
// expected-note {{implicit deduction guide declared as 'template <class Y = A> requires __is_deducible(test11::AFoo, Foo<Y>) AFoo() -> Foo<Y>'}}

AFoo s = {1}; // expected-error {{no viable constructor or deduction guide for deduction of template arguments of 'AFoo'}}
} // namespace test11
Expand Down Expand Up @@ -211,9 +211,9 @@ template<typename> concept False = false;
template<False W>
using BFoo = AFoo<W>; // expected-note {{candidate template ignored: constraints not satisfied [with V = int]}} \
// expected-note {{cannot deduce template arguments for 'BFoo' from 'Foo<int *>'}} \
// expected-note {{implicit deduction guide declared as 'template <class V> requires __is_deducible(AFoo, Foo<type-parameter-0-0 *>) && __is_deducible(test15::BFoo, Foo<type-parameter-0-0 *>) BFoo(type-parameter-0-0 *) -> Foo<type-parameter-0-0 *>}} \
// expected-note {{candidate template ignored: could not match 'Foo<type-parameter-0-0 *>' against 'int *'}} \
// expected-note {{template <class V> requires __is_deducible(AFoo, Foo<type-parameter-0-0 *>) && __is_deducible(test15::BFoo, Foo<type-parameter-0-0 *>) BFoo(Foo<type-parameter-0-0 *>) -> Foo<type-parameter-0-0 *>}}
// expected-note {{implicit deduction guide declared as 'template <class V> requires __is_deducible(AFoo, Foo<V *>) && __is_deducible(test15::BFoo, Foo<V *>) BFoo(V *) -> Foo<V *>}} \
// expected-note {{candidate template ignored: could not match 'Foo<V *>' against 'int *'}} \
// expected-note {{template <class V> requires __is_deducible(AFoo, Foo<V *>) && __is_deducible(test15::BFoo, Foo<V *>) BFoo(Foo<V *>) -> Foo<V *>}}
int i = 0;
AFoo a1(&i); // OK, deduce Foo<int *>

Expand Down Expand Up @@ -263,12 +263,12 @@ template<typename T> requires False<T> // expected-note {{because 'int' does not
Foo(T) -> Foo<int>;

template <typename U>
using Bar = Foo<U>; // expected-note {{could not match 'Foo<type-parameter-0-0>' against 'int'}} \
// expected-note {{implicit deduction guide declared as 'template <typename U> requires __is_deducible(test18::Bar, Foo<type-parameter-0-0>) Bar(Foo<type-parameter-0-0>) -> Foo<type-parameter-0-0>'}} \
using Bar = Foo<U>; // expected-note {{could not match 'Foo<U>' against 'int'}} \
// expected-note {{implicit deduction guide declared as 'template <typename U> requires __is_deducible(test18::Bar, Foo<U>) Bar(Foo<U>) -> Foo<U>'}} \
// expected-note {{candidate template ignored: constraints not satisfied}} \
// expected-note {{implicit deduction guide declared as 'template <typename T> requires False<type-parameter-0-0> && __is_deducible(test18::Bar, Foo<int>) Bar(type-parameter-0-0) -> Foo<int>'}} \
// expected-note {{implicit deduction guide declared as 'template <typename T> requires False<T> && __is_deducible(test18::Bar, Foo<int>) Bar(T) -> Foo<int>'}} \
// expected-note {{candidate function template not viable}} \
// expected-note {{implicit deduction guide declared as 'template <typename U> requires __is_deducible(test18::Bar, Foo<type-parameter-0-0>) Bar() -> Foo<type-parameter-0-0>'}}
// expected-note {{implicit deduction guide declared as 'template <typename U> requires __is_deducible(test18::Bar, Foo<U>) Bar() -> Foo<U>'}}

Bar s = {1}; // expected-error {{no viable constructor or deduction guide for deduction of template arguments}}
} // namespace test18
Expand Down Expand Up @@ -296,8 +296,8 @@ class Foo {};
// Verify that template template type parameter TTP is referenced/used in the
// template arguments of the RHS.
template <template<typename> typename TTP>
using Bar = Foo<K<TTP>>; // expected-note {{candidate template ignored: could not match 'Foo<K<template-parameter-0-0>>' against 'int'}} \
// expected-note {{implicit deduction guide declared as 'template <template <typename> typename TTP> requires __is_deducible(test20::Bar, Foo<K<template-parameter-0-0>>) Bar(Foo<K<template-parameter-0-0>>) -> Foo<K<template-parameter-0-0>>'}}
using Bar = Foo<K<TTP>>; // expected-note {{candidate template ignored: could not match 'Foo<K<TTP>>' against 'int'}} \
// expected-note {{implicit deduction guide declared as 'template <template <typename> typename TTP> requires __is_deducible(test20::Bar, Foo<K<TTP>>) Bar(Foo<K<TTP>>) -> Foo<K<TTP>>'}}

template <class T>
class Container {};
Expand Down
83 changes: 83 additions & 0 deletions clang/test/SemaTemplate/alias-template-deprecated.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
//
// This test checks that a deprecated attribute on an alias
// template triggers a warning diagnostic when it is used.

template <typename T>
struct NoAttr {
void foo() {}
};

// expected-note@+2 7{{'UsingWithAttr' has been explicitly marked deprecated here}}
template <typename T>
using UsingWithAttr __attribute__((deprecated)) = NoAttr<T>;

// expected-note@+1 {{'UsingInstWithAttr' has been explicitly marked deprecated here}}
using UsingInstWithAttr __attribute__((deprecated)) = NoAttr<int>;

// expected-note@+1 {{'TDWithAttr' has been explicitly marked deprecated here}}
typedef NoAttr<int> TDWithAttr __attribute__((deprecated));

// expected-warning@+1 {{'UsingWithAttr' is deprecated}}
typedef UsingWithAttr<int> TDUsingWithAttr;

typedef NoAttr<int> TDNoAttr;

// expected-note@+1 {{'UsingTDWithAttr' has been explicitly marked deprecated here}}
using UsingTDWithAttr __attribute__((deprecated)) = TDNoAttr;

struct S {
NoAttr<float> f1;
// expected-warning@+1 {{'UsingWithAttr' is deprecated}}
UsingWithAttr<float> f2;
};

// expected-warning@+1 {{'UsingWithAttr' is deprecated}}
void foo(NoAttr<short> s1, UsingWithAttr<short> s2) {
}

// expected-note@+2 {{'UsingWithCPPAttr' has been explicitly marked deprecated here}}
template <typename T>
using UsingWithCPPAttr [[deprecated]] = NoAttr<T>;

// expected-note@+1 {{'UsingInstWithCPPAttr' has been explicitly marked deprecated here}}
using UsingInstWithCPPAttr [[deprecated("Do not use this")]] = NoAttr<int>;

void bar() {
NoAttr<int> obj; // Okay

// expected-warning@+2 {{'UsingWithAttr' is deprecated}}
// expected-note@+1 {{in instantiation of template type alias 'UsingWithAttr' requested here}}
UsingWithAttr<int> objUsingWA;

// expected-warning@+2 {{'UsingWithAttr' is deprecated}}
// expected-note@+1 {{in instantiation of template type alias 'UsingWithAttr' requested here}}
NoAttr<UsingWithAttr<int>> s;

// expected-note@+1 {{'DepInt' has been explicitly marked deprecated here}}
using DepInt [[deprecated]] = int;
// expected-warning@+3 {{'UsingWithAttr' is deprecated}}
// expected-warning@+2 {{'DepInt' is deprecated}}
// expected-note@+1 {{in instantiation of template type alias 'UsingWithAttr' requested here}}
using X = UsingWithAttr<DepInt>;

// expected-warning@+2 {{'UsingWithAttr' is deprecated}}
// expected-note@+1 {{in instantiation of template type alias 'UsingWithAttr' requested here}}
UsingWithAttr<int>().foo();

// expected-warning@+1 {{'UsingInstWithAttr' is deprecated}}
UsingInstWithAttr objUIWA;

// expected-warning@+1 {{'TDWithAttr' is deprecated}}
TDWithAttr objTDWA;

// expected-warning@+1 {{'UsingTDWithAttr' is deprecated}}
UsingTDWithAttr objUTDWA;

// expected-warning@+2 {{'UsingWithCPPAttr' is deprecated}}
// expected-note@+1 {{in instantiation of template type alias 'UsingWithCPPAttr' requested here}}
UsingWithCPPAttr<int> objUsingWCPPA;

// expected-warning@+1 {{'UsingInstWithCPPAttr' is deprecated: Do not use this}}
UsingInstWithCPPAttr objUICPPWA;
}
Loading