142 changes: 142 additions & 0 deletions bolt/unittests/Core/MemoryMaps.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
//===- bolt/unittest/Core/MemoryMaps.cpp ----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "bolt/Core/BinaryContext.h"
#include "bolt/Profile/DataAggregator.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Testing/Support/Error.h"
#include "gtest/gtest.h"

using namespace llvm;
using namespace llvm::object;
using namespace llvm::ELF;
using namespace bolt;

namespace opts {
extern cl::opt<std::string> ReadPerfEvents;
} // namespace opts

namespace {

/// Perform checks on memory map events normally captured in perf. Tests use
/// the 'opts::ReadPerfEvents' flag to emulate these events, passing a custom
/// 'perf script' output to DataAggregator.
struct MemoryMapsTester : public testing::TestWithParam<Triple::ArchType> {
void SetUp() override {
initalizeLLVM();
prepareElf();
initializeBOLT();
}

protected:
void initalizeLLVM() {
llvm::InitializeAllTargetInfos();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllAsmParsers();
llvm::InitializeAllDisassemblers();
llvm::InitializeAllTargets();
llvm::InitializeAllAsmPrinters();
}

void prepareElf() {
memcpy(ElfBuf, "\177ELF", 4);
ELF64LE::Ehdr *EHdr = reinterpret_cast<typename ELF64LE::Ehdr *>(ElfBuf);
EHdr->e_ident[llvm::ELF::EI_CLASS] = llvm::ELF::ELFCLASS64;
EHdr->e_ident[llvm::ELF::EI_DATA] = llvm::ELF::ELFDATA2LSB;
EHdr->e_machine = GetParam() == Triple::aarch64 ? EM_AARCH64 : EM_X86_64;
MemoryBufferRef Source(StringRef(ElfBuf, sizeof(ElfBuf)), "ELF");
ObjFile = cantFail(ObjectFile::createObjectFile(Source));
}

void initializeBOLT() {
Relocation::Arch = ObjFile->makeTriple().getArch();
BC = cantFail(BinaryContext::createBinaryContext(
ObjFile->makeTriple(), ObjFile->getFileName(), nullptr, true,
DWARFContext::create(*ObjFile.get()), {llvm::outs(), llvm::errs()}));
ASSERT_FALSE(!BC);
}

char ElfBuf[sizeof(typename ELF64LE::Ehdr)] = {};
std::unique_ptr<ObjectFile> ObjFile;
std::unique_ptr<BinaryContext> BC;
};
} // namespace

#ifdef X86_AVAILABLE

INSTANTIATE_TEST_SUITE_P(X86, MemoryMapsTester,
::testing::Values(Triple::x86_64));

#endif

#ifdef AARCH64_AVAILABLE

INSTANTIATE_TEST_SUITE_P(AArch64, MemoryMapsTester,
::testing::Values(Triple::aarch64));

#endif

/// Check that the correct mmap size is computed when we have multiple text
/// segment mappings.
TEST_P(MemoryMapsTester, ParseMultipleSegments) {
const int Pid = 1234;
StringRef Filename = "BINARY";
opts::ReadPerfEvents = formatv(
"name 0 [000] 0.000000: PERF_RECORD_MMAP2 {0}/{0}: "
"[0xabc0000000(0x1000000) @ 0x11c0000 103:01 1573523 0]: r-xp {1}\n"
"name 0 [000] 0.000000: PERF_RECORD_MMAP2 {0}/{0}: "
"[0xabc2000000(0x8000000) @ 0x31d0000 103:01 1573523 0]: r-xp {1}\n",
Pid, Filename);

BC->SegmentMapInfo[0x11da000] =
SegmentInfo{0x11da000, 0x10da000, 0x11ca000, 0x10da000, 0x10000, true};
BC->SegmentMapInfo[0x31d0000] =
SegmentInfo{0x31d0000, 0x51ac82c, 0x31d0000, 0x3000000, 0x200000, true};

DataAggregator DA("");
BC->setFilename(Filename);
Error Err = DA.preprocessProfile(*BC);

// Ignore errors from perf2bolt when parsing memory events later on.
ASSERT_THAT_ERROR(std::move(Err), Succeeded());

auto &BinaryMMapInfo = DA.getBinaryMMapInfo();
auto El = BinaryMMapInfo.find(Pid);
// Check that memory mapping is present and has the expected size.
ASSERT_NE(El, BinaryMMapInfo.end());
ASSERT_EQ(El->second.Size, static_cast<uint64_t>(0xb1d0000));
}

/// Check that DataAggregator aborts when pre-processing an input binary
/// with multiple text segments that have different base addresses.
TEST_P(MemoryMapsTester, MultipleSegmentsMismatchedBaseAddress) {
const int Pid = 1234;
StringRef Filename = "BINARY";
opts::ReadPerfEvents = formatv(
"name 0 [000] 0.000000: PERF_RECORD_MMAP2 {0}/{0}: "
"[0xabc0000000(0x1000000) @ 0x11c0000 103:01 1573523 0]: r-xp {1}\n"
"name 0 [000] 0.000000: PERF_RECORD_MMAP2 {0}/{0}: "
"[0xabc2000000(0x8000000) @ 0x31d0000 103:01 1573523 0]: r-xp {1}\n",
Pid, Filename);

BC->SegmentMapInfo[0x11da000] =
SegmentInfo{0x11da000, 0x10da000, 0x11ca000, 0x10da000, 0x10000, true};
// Using '0x31d0fff' FileOffset which triggers a different base address
// for this second text segment.
BC->SegmentMapInfo[0x31d0000] =
SegmentInfo{0x31d0000, 0x51ac82c, 0x31d0fff, 0x3000000, 0x200000, true};

DataAggregator DA("");
BC->setFilename(Filename);
ASSERT_DEBUG_DEATH(
{ Error Err = DA.preprocessProfile(*BC); },
"Base address on multiple segment mappings should match");
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//

#include "ReturnConstRefFromParameterCheck.h"
#include "clang/AST/Attrs.inc"
#include "clang/AST/Expr.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
Expand All @@ -15,14 +16,23 @@ using namespace clang::ast_matchers;

namespace clang::tidy::bugprone {

namespace {

AST_MATCHER(ParmVarDecl, hasLifetimeBoundAttr) {
return Node.hasAttr<LifetimeBoundAttr>();
}

} // namespace

void ReturnConstRefFromParameterCheck::registerMatchers(MatchFinder *Finder) {
const auto DRef = ignoringParens(
declRefExpr(
to(parmVarDecl(hasType(hasCanonicalType(
qualType(lValueReferenceType(pointee(
qualType(isConstQualified()))))
.bind("type"))),
hasDeclContext(functionDecl().bind("owner")))
hasDeclContext(functionDecl().bind("owner")),
unless(hasLifetimeBoundAttr()))
.bind("param")))
.bind("dref"));
const auto Func =
Expand Down
7 changes: 5 additions & 2 deletions clang-tools-extra/clang-tidy/misc/UseInternalLinkageCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,11 @@ void UseInternalLinkageCheck::registerMatchers(MatchFinder *Finder) {
isExternStorageClass(), isExternC(),
// 3. template
isExplicitTemplateSpecialization(),
// 4. friend
hasAncestor(friendDecl()))));
hasAncestor(decl(anyOf(
// 4. friend
friendDecl(),
// 5. module export decl
exportDecl()))))));
Finder->addMatcher(
functionDecl(Common, hasBody(),
unless(anyOf(cxxMethodDecl(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,10 @@ namespace clang::tidy::readability {
/// a call to `empty()`.
///
/// The emptiness of a container should be checked using the `empty()` method
/// instead of the `size()` method. It is not guaranteed that `size()` is a
/// constant-time function, and it is generally more efficient and also shows
/// clearer intent to use `empty()`. Furthermore some containers may implement
/// the `empty()` method but not implement the `size()` method. Using `empty()`
/// whenever possible makes it easier to switch to another container in the
/// future.
/// instead of the `size()` method. It shows clearer intent to use `empty()`.
/// Furthermore some containers may implement the `empty()` method but not
/// implement the `size()` method. Using `empty()` whenever possible makes it
/// easier to switch to another container in the future.
class ContainerSizeEmptyCheck : public ClangTidyCheck {
public:
ContainerSizeEmptyCheck(StringRef Name, ClangTidyContext *Context);
Expand Down
2 changes: 1 addition & 1 deletion clang-tools-extra/clangd/index/BackgroundRebuild.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//===-- BackgroundRebuild.cpp - when to rebuild thei background index -----===//
//===-- BackgroundRebuild.cpp - when to rebuild the background index ------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
Expand Down
6 changes: 4 additions & 2 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,8 @@ Changes in existing checks
<clang-tidy/checks/bugprone/return-const-ref-from-parameter>` check to
diagnose potential dangling references when returning a ``const &`` parameter
by using the conditional operator ``cond ? var1 : var2`` and no longer giving
false positives for functions which contain lambda.
false positives for functions which contain lambda and ignore parameters
with ``[[clang::lifetimebound]]`` attribute.

- Improved :doc:`bugprone-sizeof-expression
<clang-tidy/checks/bugprone/sizeof-expression>` check to find suspicious
Expand Down Expand Up @@ -248,7 +249,8 @@ Changes in existing checks
<clang-tidy/checks/misc/use-internal-linkage>` check to insert ``static``
keyword before type qualifiers such as ``const`` and ``volatile`` and fix
false positives for function declaration without body and fix false positives
for global scoped overloaded ``operator new`` and ``operator delete``.
for C++20 export declarations and fix false positives for global scoped
overloaded ``operator new`` and ``operator delete``.

- Improved :doc:`modernize-avoid-c-arrays
<clang-tidy/checks/modernize/avoid-c-arrays>` check to suggest using
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,6 @@ after the call. When the function returns such a parameter also as constant refe
then the returned reference can be used after the object it refers to has been
destroyed.

This issue can be resolved by declaring an overload of the problematic function
where the ``const &`` parameter is instead declared as ``&&``. The developer has
to ensure that the implementation of that function does not produce a
use-after-free, the exact error that this check is warning against.
Marking such an ``&&`` overload as ``deleted``, will silence the warning as
well. In the case of different ``const &`` parameters being returned depending
on the control flow of the function, an overload where all problematic
``const &`` parameters have been declared as ``&&`` will resolve the issue.

Example
-------

Expand All @@ -38,3 +29,23 @@ Example

const S& s = fn(S{1});
s.v; // use after free


This issue can be resolved by declaring an overload of the problematic function
where the ``const &`` parameter is instead declared as ``&&``. The developer has
to ensure that the implementation of that function does not produce a
use-after-free, the exact error that this check is warning against.
Marking such an ``&&`` overload as ``deleted``, will silence the warning as
well. In the case of different ``const &`` parameters being returned depending
on the control flow of the function, an overload where all problematic
``const &`` parameters have been declared as ``&&`` will resolve the issue.

This issue can also be resolved by adding ``[[clang::lifetimebound]]``. Clang
enable ``-Wdangling`` warning by default which can detect mis-uses of the
annotated function. See `lifetimebound attribute <https://clang.llvm.org/docs/AttributeReference.html#id11>`_
for details.

.. code-block:: c++

const int &f(const int &a [[clang::lifetimebound]]) { return a; } // no warning
const int &v = f(1); // warning: temporary bound to local reference 'v' will be destroyed at the end of the full-expression [-Wdangling]
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ Example:
void fn3(); // without function body in all declaration, maybe external linkage
void fn3();

// export declarations
export void fn4() {}
export namespace t { void fn5() {} }
export int v2;

Options
-------

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,10 @@ Checks whether a call to the ``size()``/``length()`` method can be replaced
with a call to ``empty()``.

The emptiness of a container should be checked using the ``empty()`` method
instead of the ``size()``/``length()`` method. It is not guaranteed that
``size()``/``length()`` is a constant-time function, and it is generally more
efficient and also shows clearer intent to use ``empty()``. Furthermore some
containers may implement the ``empty()`` method but not implement the ``size()``
or ``length()`` method. Using ``empty()`` whenever possible makes it easier to
switch to another container in the future.
instead of the ``size()``/``length()`` method. It shows clearer intent to use
``empty()``. Furthermore some containers may implement the ``empty()`` method
but not implement the ``size()`` or ``length()`` method. Using ``empty()``
whenever possible makes it easier to switch to another container in the future.

The check issues warning if a container has ``empty()`` and ``size()`` or
``length()`` methods matching following signatures:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,3 +197,9 @@ int const &overload_params_difference3(int p1, int const &a, int p2) { return a;
int const &overload_params_difference3(int p1, long &&a, int p2);

} // namespace overload

namespace gh117696 {
namespace use_lifetime_bound_attr {
int const &f(int const &a [[clang::lifetimebound]]) { return a; }
} // namespace use_lifetime_bound_attr
} // namespace gh117696
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// RUN: %check_clang_tidy -std=c++20 %s misc-use-internal-linkage %t -- -- -I%S/Inputs/use-internal-linkage

module;

export module test;

export void single_export_fn() {}
export int single_export_var;

export {
void group_export_fn1() {}
void group_export_fn2() {}
int group_export_var1;
int group_export_var2;
}

export namespace aa {
void namespace_export_fn() {}
int namespace_export_var;
} // namespace aa
2 changes: 1 addition & 1 deletion clang/docs/ClangFormat.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ to format C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# code.
supported:
CSharp: .cs
Java: .java
JavaScript: .mjs .js .ts
JavaScript: .js .mjs .cjs .ts
Json: .json
Objective-C: .m .mm
Proto: .proto .protodevel
Expand Down
12 changes: 10 additions & 2 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -648,7 +648,7 @@ elementwise to the input.
Unless specified otherwise operation(±0) = ±0 and operation(±infinity) = ±infinity

The integer elementwise intrinsics, including ``__builtin_elementwise_popcount``,
can be called in a ``constexpr`` context.
``__builtin_elementwise_bitreverse``, can be called in a ``constexpr`` context.

============================================== ====================================================================== =========================================
Name Operation Supported element types
Expand Down Expand Up @@ -1989,7 +1989,7 @@ Enumerations with a fixed underlying type
-----------------------------------------
Clang provides support for C++11 enumerations with a fixed underlying type
within Objective-C. For example, one can write an enumeration type as:
within Objective-C and C `prior to C23 <https://open-std.org/JTC1/SC22/WG14/www/docs/n3030.htm>`_. For example, one can write an enumeration type as:
.. code-block:: c++
Expand All @@ -2001,6 +2001,14 @@ value, is ``unsigned char``.
Use ``__has_feature(objc_fixed_enum)`` to determine whether support for fixed
underlying types is available in Objective-C.
Use ``__has_extension(c_fixed_enum)`` to determine whether support for fixed
underlying types is available in C prior to C23. This will also report ``true`` in C23
and later modes as the functionality is available even if it's not an extension in
those modes.
Use ``__has_feature(c_fixed_enum)`` to determine whether support for fixed
underlying types is available in C23 and later.
Interoperability with C++11 lambdas
-----------------------------------
Expand Down
11 changes: 11 additions & 0 deletions clang/docs/LibASTMatchersReference.html
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,17 @@ <h2 id="decl-matchers">Node Matchers</h2>
</pre></td></tr>


<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('exportDecl0')"><a name="exportDecl0Anchor">exportDecl</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1ExportDecl.html">ExportDecl</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="exportDecl0"><pre>Matches any export declaration.

Example matches following declarations.
export void foo();
export { void foo(); }
export namespace { void foo(); }
export int v;
</pre></td></tr>


<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('fieldDecl0')"><a name="fieldDecl0Anchor">fieldDecl</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1FieldDecl.html">FieldDecl</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="fieldDecl0"><pre>Matches field declarations.

Expand Down
20 changes: 17 additions & 3 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,8 @@ C++2c Feature Support
- Added the ``__builtin_is_within_lifetime`` builtin, which supports
`P2641R4 Checking if a union alternative is active <https://wg21.link/p2641r4>`_

- Implemented `P3176R1 The Oxford variadic comma <https://wg21.link/P3176R1>`_

C++23 Feature Support
^^^^^^^^^^^^^^^^^^^^^
- Removed the restriction to literal types in constexpr functions in C++23 mode.
Expand Down Expand Up @@ -308,6 +310,9 @@ Resolutions to C++ Defect Reports
by default.
(`CWG2521: User-defined literals and reserved identifiers <https://cplusplus.github.io/CWG/issues/2521.html>`_).

- Fix name lookup for a dependent base class that is the current instantiation.
(`CWG591: When a dependent base class is the current instantiation <https://cplusplus.github.io/CWG/issues/591.html>`_).

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

Expand Down Expand Up @@ -402,6 +407,7 @@ Non-comprehensive list of changes in this release
- ``__builtin_reduce_and`` function can now be used in constant expressions.
- ``__builtin_reduce_or`` and ``__builtin_reduce_xor`` functions can now be used in constant expressions.
- ``__builtin_elementwise_popcount`` function can now be used in constant expressions.
- ``__builtin_elementwise_bitreverse`` function can now be used in constant expressions.

New Compiler Flags
------------------
Expand Down Expand Up @@ -624,9 +630,6 @@ Improvements to Clang's diagnostics

- Fixed a false negative ``-Wunused-private-field`` diagnostic when a defaulted comparison operator is defined out of class (#GH116961).

- Clang now supports using alias templates in deduction guides, aligning with the C++ standard,
which treats alias templates as synonyms for their underlying types (#GH54909).

- Clang now diagnoses dangling references for C++20's parenthesized aggregate initialization (#101957).

Improvements to Clang's time-trace
Expand Down Expand Up @@ -763,6 +766,9 @@ Bug Fixes to C++ Support
- Fixed a bug where bounds of partially expanded pack indexing expressions were checked too early. (#GH116105)
- Fixed an assertion failure caused by using ``consteval`` in condition in consumed analyses. (#GH117385)
- Fix a crash caused by incorrect argument position in merging deduced template arguments. (#GH113659)
- Fixed an assertion failure caused by mangled names with invalid identifiers. (#GH112205)
- Fixed an incorrect lambda scope of generic lambdas that caused Clang to crash when computing potential lambda
captures at the end of a full expression. (#GH115931)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -965,6 +971,14 @@ AST Matchers
- Ensure ``hasName`` matches template specializations across inline namespaces,
making `matchesNodeFullSlow` and `matchesNodeFullFast` consistent.

- Improved the performance of the ``getExpansionLocOfMacro`` by tracking already processed macros during recursion.

- Add ``exportDecl`` matcher to match export declaration.

- Ensure ``hasType`` and ``hasDeclaration`` match Objective-C interface declarations.

- Ensure ``pointee`` matches Objective-C pointer types.

clang-format
------------

Expand Down
9 changes: 7 additions & 2 deletions clang/docs/tools/dump_ast_matchers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import collections
import re
import os

try:
from urllib.request import urlopen
Expand All @@ -18,7 +19,11 @@
CLASS_INDEX_PAGE = None
print("Unable to get %s: %s" % (CLASS_INDEX_PAGE_URL, e))

MATCHERS_FILE = "../../include/clang/ASTMatchers/ASTMatchers.h"
CURRENT_DIR = os.path.dirname(__file__)
MATCHERS_FILE = os.path.join(
CURRENT_DIR, "../../include/clang/ASTMatchers/ASTMatchers.h"
)
HTML_FILE = os.path.join(CURRENT_DIR, "../LibASTMatchersReference.html")

# Each matcher is documented in one row of the form:
# result | name | argA
Expand Down Expand Up @@ -590,7 +595,7 @@ def sort_table(matcher_type, matcher_map):
narrowing_matcher_table = sort_table("NARROWING", narrowing_matchers)
traversal_matcher_table = sort_table("TRAVERSAL", traversal_matchers)

reference = open("../LibASTMatchersReference.html").read()
reference = open(HTML_FILE).read()
reference = re.sub(
r"<!-- START_DECL_MATCHERS.*END_DECL_MATCHERS -->",
node_matcher_table,
Expand Down
16 changes: 14 additions & 2 deletions clang/include/clang/ASTMatchers/ASTMatchers.h
Original file line number Diff line number Diff line change
Expand Up @@ -1236,6 +1236,17 @@ AST_MATCHER_P(TemplateArgument, equalsIntegralValue,
extern const internal::VariadicDynCastAllOfMatcher<Stmt,
ObjCAutoreleasePoolStmt> autoreleasePoolStmt;

/// Matches any export declaration.
///
/// Example matches following declarations.
/// \code
/// export void foo();
/// export { void foo(); }
/// export namespace { void foo(); }
/// export int v;
/// \endcode
extern const internal::VariadicDynCastAllOfMatcher<Decl, ExportDecl> exportDecl;

/// Matches any value declaration.
///
/// Example matches A, B, C and F
Expand Down Expand Up @@ -4033,7 +4044,7 @@ AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
hasType,
AST_POLYMORPHIC_SUPPORTED_TYPES(Expr, FriendDecl, ValueDecl,
CXXBaseSpecifier),
CXXBaseSpecifier, ObjCInterfaceDecl),
internal::Matcher<Decl>, InnerMatcher, 1) {
QualType QT = internal::getUnderlyingType(Node);
if (!QT.isNull())
Expand Down Expand Up @@ -7434,7 +7445,8 @@ extern const AstTypeMatcher<RValueReferenceType> rValueReferenceType;
AST_TYPELOC_TRAVERSE_MATCHER_DECL(
pointee, getPointee,
AST_POLYMORPHIC_SUPPORTED_TYPES(BlockPointerType, MemberPointerType,
PointerType, ReferenceType));
PointerType, ReferenceType,
ObjCObjectPointerType));

/// Matches typedef types.
///
Expand Down
10 changes: 9 additions & 1 deletion clang/include/clang/ASTMatchers/ASTMatchersInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@ inline QualType getUnderlyingType(const FriendDecl &Node) {
inline QualType getUnderlyingType(const CXXBaseSpecifier &Node) {
return Node.getType();
}
inline QualType getUnderlyingType(const ObjCInterfaceDecl &Node) {
return Node.getTypeForDecl()->getPointeeType();
}

/// Unifies obtaining a `TypeSourceInfo` from different node types.
template <typename T,
Expand Down Expand Up @@ -1113,6 +1116,11 @@ class HasDeclarationMatcher : public MatcherInterface<T> {
return matchesDecl(Node.getDecl(), Finder, Builder);
}

bool matchesSpecialized(const ObjCInterfaceDecl &Node, ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
return matchesDecl(Node.getCanonicalDecl(), Finder, Builder);
}

/// Extracts the operator new of the new call and returns whether the
/// inner matcher matches on it.
bool matchesSpecialized(const CXXNewExpr &Node,
Expand Down Expand Up @@ -1213,7 +1221,7 @@ using HasDeclarationSupportedTypes =
ElaboratedType, InjectedClassNameType, LabelStmt, AddrLabelExpr,
MemberExpr, QualType, RecordType, TagType,
TemplateSpecializationType, TemplateTypeParmType, TypedefType,
UnresolvedUsingType, ObjCIvarRefExpr>;
UnresolvedUsingType, ObjCIvarRefExpr, ObjCInterfaceDecl>;

/// A Matcher that allows binding the node it matches to an id.
///
Expand Down
14 changes: 13 additions & 1 deletion clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -1270,7 +1270,7 @@ def ElementwiseATan2 : Builtin {

def ElementwiseBitreverse : Builtin {
let Spellings = ["__builtin_elementwise_bitreverse"];
let Attributes = [NoThrow, Const, CustomTypeChecking];
let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

Expand Down Expand Up @@ -4738,6 +4738,12 @@ def GetDeviceSideMangledName : LangBuiltin<"CUDA_LANG"> {
}

// HLSL
def HLSLResourceGetPointer : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_resource_getpointer"];
let Attributes = [NoThrow];
let Prototype = "void(...)";
}

def HLSLAll : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_all"];
let Attributes = [NoThrow, Const];
Expand Down Expand Up @@ -4924,6 +4930,12 @@ def HLSLClip: LangBuiltin<"HLSL_LANG"> {
let Prototype = "void(...)";
}

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

// Builtins for XRay.
def XRayCustomEvent : Builtin {
let Spellings = ["__xray_customevent"];
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/BuiltinsAMDGPU.def
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,8 @@ TARGET_BUILTIN(__builtin_amdgcn_ds_read_tr4_b64_v2i32, "V2iV2i*3", "nc", "gfx950
TARGET_BUILTIN(__builtin_amdgcn_ds_read_tr6_b96_v3i32, "V3iV3i*3", "nc", "gfx950-insts")
TARGET_BUILTIN(__builtin_amdgcn_ds_read_tr8_b64_v2i32, "V2iV2i*3", "nc", "gfx950-insts")
TARGET_BUILTIN(__builtin_amdgcn_ds_read_tr16_b64_v4i16, "V4sV4s*3", "nc", "gfx950-insts")
TARGET_BUILTIN(__builtin_amdgcn_ds_read_tr16_b64_v4f16, "V4hV4h*3", "nc", "gfx950-insts")
TARGET_BUILTIN(__builtin_amdgcn_ds_read_tr16_b64_v4bf16, "V4yV4y*3", "nc", "gfx950-insts")

TARGET_BUILTIN(__builtin_amdgcn_ashr_pk_i8_i32, "UsUiUiUi", "nc", "ashr-pk-insts")
TARGET_BUILTIN(__builtin_amdgcn_ashr_pk_u8_i32, "UsUiUiUi", "nc", "ashr-pk-insts")
Expand Down
4 changes: 3 additions & 1 deletion clang/include/clang/Basic/DiagnosticGroups.td
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ def DeprecatedWritableStr : DiagGroup<"deprecated-writable-strings",
[CXX11CompatDeprecatedWritableStr]>;
def DeprecatedPragma : DiagGroup<"deprecated-pragma">;
def DeprecatedType : DiagGroup<"deprecated-type">;
def DeprecatedMissingCommaVariadicParam : DiagGroup<"deprecated-missing-comma-variadic-parameter">;
// FIXME: Why is DeprecatedImplementations not in this group?
def Deprecated : DiagGroup<"deprecated", [DeprecatedAnonEnumEnumConversion,
DeprecatedArrayCompare,
Expand All @@ -235,7 +236,8 @@ def Deprecated : DiagGroup<"deprecated", [DeprecatedAnonEnumEnumConversion,
DeprecatedType,
DeprecatedVolatile,
DeprecatedWritableStr,
DeprecatedRedundantConstexprStaticDef
DeprecatedRedundantConstexprStaticDef,
DeprecatedMissingCommaVariadicParam
]>,
DiagCategory<"Deprecations">;

Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,9 @@ def err_function_scope_depth_exceeded : Error<
"function scope depth exceeded maximum of %0">, DefaultFatal;
def err_missing_comma_before_ellipsis : Error<
"C requires a comma prior to the ellipsis in a variadic function type">;
def warn_deprecated_missing_comma_before_ellipsis : Warning<
"declaration of a variadic function without a comma before '...' is deprecated">,
InGroup<DeprecatedMissingCommaVariadicParam>;
def err_unexpected_typedef_ident : Error<
"unexpected type name %0: expected identifier">;
def warn_cxx98_compat_decltype : Warning<
Expand Down
10 changes: 5 additions & 5 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -12733,19 +12733,19 @@ def err_acc_size_expr_value
"OpenACC 'tile' clause size expression must be %select{an asterisk "
"or a constant expression|positive integer value, evaluated to %1}0">;
def err_acc_invalid_in_loop
: Error<"%select{OpenACC '%2' construct|while loop|do loop}0 cannot appear "
"in intervening code of a 'loop' with a '%1' clause">;
: Error<"%select{OpenACC '%3' construct|while loop|do loop}0 cannot appear "
"in intervening code of a '%1' with a '%2' clause">;
def note_acc_active_clause_here
: Note<"active '%0' clause defined here">;
def err_acc_clause_multiple_loops
: Error<"more than one for-loop in a loop associated with OpenACC 'loop' "
"construct with a '%select{collapse|tile}0' clause">;
: Error<"more than one for-loop in a loop associated with OpenACC '%0' "
"construct with a '%1' clause">;
def err_acc_insufficient_loops
: Error<"'%0' clause specifies a loop count greater than the number "
"of available loops">;
def err_acc_intervening_code
: Error<"inner loops must be tightly nested inside a '%0' clause on "
"a 'loop' construct">;
"a '%1' construct">;
def err_acc_gang_multiple_elt
: Error<"OpenACC 'gang' clause may have at most one %select{unnamed or "
"'num'|'dim'|'static'}0 argument">;
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ FEATURE(c_atomic, LangOpts.C11)
FEATURE(c_generic_selections, LangOpts.C11)
FEATURE(c_static_assert, LangOpts.C11)
FEATURE(c_thread_local, LangOpts.C11 &&PP.getTargetInfo().isTLSSupported())
// C23 features
FEATURE(c_fixed_enum, LangOpts.C23)
// C++11 features
FEATURE(cxx_access_control_sfinae, LangOpts.CPlusPlus11)
FEATURE(cxx_alias_templates, LangOpts.CPlusPlus11)
Expand Down Expand Up @@ -269,6 +271,7 @@ EXTENSION(c_static_assert, true)
EXTENSION(c_thread_local, PP.getTargetInfo().isTLSSupported())
// C23 features supported by other languages as extensions
EXTENSION(c_attributes, true)
EXTENSION(c_fixed_enum, true)
// C++11 features supported by other languages as extensions.
EXTENSION(cxx_atomic, LangOpts.CPlusPlus)
EXTENSION(cxx_default_function_template_args, LangOpts.CPlusPlus)
Expand Down
28 changes: 14 additions & 14 deletions clang/include/clang/Basic/arm_sve.td
Original file line number Diff line number Diff line change
Expand Up @@ -762,14 +762,14 @@ def SVCMPLS_WIDE_N : SInst<"svcmple_wide[_n_{d}]", "PPdj", "UcUsUi", MergeNone,
////////////////////////////////////////////////////////////////////////////////
// While comparisons

def SVWHILELE_S32 : SInst<"svwhilele_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilele", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELE_S64 : SInst<"svwhilele_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilele", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELO_U32 : SInst<"svwhilelt_{d}[_{1}]", "Pmm", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilelo", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELO_U64 : SInst<"svwhilelt_{d}[_{1}]", "Pnn", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilelo", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELS_U32 : SInst<"svwhilele_{d}[_{1}]", "Pmm", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilels", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELS_U64 : SInst<"svwhilele_{d}[_{1}]", "Pnn", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilels", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELT_S32 : SInst<"svwhilelt_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilelt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELT_S64 : SInst<"svwhilelt_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilelt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELE_S32 : SInst<"svwhilele_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilele", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELE_S64 : SInst<"svwhilele_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilele", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELO_U32 : SInst<"svwhilelt_{d}[_{1}]", "Pmm", "PcPsPiPl", MergeNone, "aarch64_sve_whilelo", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELO_U64 : SInst<"svwhilelt_{d}[_{1}]", "Pnn", "PcPsPiPl", MergeNone, "aarch64_sve_whilelo", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELS_U32 : SInst<"svwhilele_{d}[_{1}]", "Pmm", "PcPsPiPl", MergeNone, "aarch64_sve_whilels", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELS_U64 : SInst<"svwhilele_{d}[_{1}]", "Pnn", "PcPsPiPl", MergeNone, "aarch64_sve_whilels", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELT_S32 : SInst<"svwhilelt_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilelt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELT_S64 : SInst<"svwhilelt_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilelt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;

////////////////////////////////////////////////////////////////////////////////
// Counting bit
Expand Down Expand Up @@ -1365,10 +1365,10 @@ def SVWHILEGE_S32 : SInst<"svwhilege_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNon
def SVWHILEGE_S64 : SInst<"svwhilege_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilege", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEGT_S32 : SInst<"svwhilegt_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilegt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEGT_S64 : SInst<"svwhilegt_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilegt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEHI_U32 : SInst<"svwhilegt_{d}[_{1}]", "Pmm", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilehi", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEHI_U64 : SInst<"svwhilegt_{d}[_{1}]", "Pnn", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilehi", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEHS_U32 : SInst<"svwhilege_{d}[_{1}]", "Pmm", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilehs", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEHS_U64 : SInst<"svwhilege_{d}[_{1}]", "Pnn", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilehs", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEHI_U32 : SInst<"svwhilegt_{d}[_{1}]", "Pmm", "PcPsPiPl", MergeNone, "aarch64_sve_whilehi", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEHI_U64 : SInst<"svwhilegt_{d}[_{1}]", "Pnn", "PcPsPiPl", MergeNone, "aarch64_sve_whilehi", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEHS_U32 : SInst<"svwhilege_{d}[_{1}]", "Pmm", "PcPsPiPl", MergeNone, "aarch64_sve_whilehs", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEHS_U64 : SInst<"svwhilege_{d}[_{1}]", "Pnn", "PcPsPiPl", MergeNone, "aarch64_sve_whilehs", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
}

let SVETargetGuard = "sve2p1", SMETargetGuard = "sme2" in {
Expand Down Expand Up @@ -2326,7 +2326,7 @@ let SVETargetGuard = "sve2p1,bf16", SMETargetGuard = "sme2p1,bf16" in {
// Multi-vector convert to/from floating-point.
//
let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in {
def SVCVT_F16_X2 : SInst<"svcvt_f16[_f32_x2]", "e2", "f", MergeNone, "aarch64_sve_fcvt_x2", [IsStreaming],[]>;
def SVCVT_F16_X2 : SInst<"svcvt_f16[_f32_x2]", "h2", "f", MergeNone, "aarch64_sve_fcvt_x2", [IsStreaming],[]>;
def SVCVT_BF16_X2 : SInst<"svcvt_bf16[_f32_x2]", "$2", "f", MergeNone, "aarch64_sve_bfcvt_x2", [IsOverloadNone, IsStreaming],[]>;

def SVCVT_F32_U32_X2 : SInst<"svcvt_{d}[_u32_x2]", "2.d2.u", "f", MergeNone, "aarch64_sve_ucvtf_x2", [IsStreaming, IsOverloadWhileOrMultiVecCvt], []>;
Expand All @@ -2348,7 +2348,7 @@ let SVETargetGuard = InvalidMode, SMETargetGuard = "sme-f16f16" in {
// Multi-vector floating-point convert from single-precision to interleaved half-precision/BFloat16
//
let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in {
def SVCVTN_F16_X2 : SInst<"svcvtn_f16[_f32_x2]", "e2", "f", MergeNone, "aarch64_sve_fcvtn_x2", [IsStreaming],[]>;
def SVCVTN_F16_X2 : SInst<"svcvtn_f16[_f32_x2]", "h2", "f", MergeNone, "aarch64_sve_fcvtn_x2", [IsStreaming],[]>;
def SVCVTN_BF16_X2 : SInst<"svcvtn_bf16[_f32_x2]", "$2", "f", MergeNone, "aarch64_sve_bfcvtn_x2", [IsOverloadNone, IsStreaming],[]>;
}

Expand Down
10 changes: 7 additions & 3 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -1786,12 +1786,12 @@ defm debug_info_for_profiling : BoolFOption<"debug-info-for-profiling",
PosFlag<SetTrue, [], [ClangOption, CC1Option],
"Emit extra debug info to make sample profile more accurate">,
NegFlag<SetFalse>>;
def fprofile_generate_cold_function_coverage : Flag<["-"], "fprofile-generate-cold-function-coverage">,
def fprofile_generate_cold_function_coverage : Flag<["-"], "fprofile-generate-cold-function-coverage">,
Group<f_Group>, Visibility<[ClangOption, CLOption]>,
HelpText<"Generate instrumented code to collect coverage info for cold functions into default.profraw file (overridden by '=' form of option or LLVM_PROFILE_FILE env var)">;
def fprofile_generate_cold_function_coverage_EQ : Joined<["-"], "fprofile-generate-cold-function-coverage=">,
def fprofile_generate_cold_function_coverage_EQ : Joined<["-"], "fprofile-generate-cold-function-coverage=">,
Group<f_Group>, Visibility<[ClangOption, CLOption]>, MetaVarName<"<directory>">,
HelpText<"Generate instrumented code to collect coverage info for cold functions into <directory>/default.profraw (overridden by LLVM_PROFILE_FILE env var)">;
HelpText<"Generate instrumented code to collect coverage info for cold functions into <directory>/default.profraw (overridden by LLVM_PROFILE_FILE env var)">;
def fprofile_instr_generate : Flag<["-"], "fprofile-instr-generate">,
Group<f_Group>, Visibility<[ClangOption, CLOption]>,
HelpText<"Generate instrumented code to collect execution counts into default.profraw file (overridden by '=' form of option or LLVM_PROFILE_FILE env var)">;
Expand Down Expand Up @@ -5092,6 +5092,10 @@ def matomics : Flag<["-"], "matomics">, Group<m_wasm_Features_Group>;
def mno_atomics : Flag<["-"], "mno-atomics">, Group<m_wasm_Features_Group>;
def mbulk_memory : Flag<["-"], "mbulk-memory">, Group<m_wasm_Features_Group>;
def mno_bulk_memory : Flag<["-"], "mno-bulk-memory">, Group<m_wasm_Features_Group>;
def mbulk_memory_opt : Flag<["-"], "mbulk-memory-opt">, Group<m_wasm_Features_Group>;
def mno_bulk_memory_opt : Flag<["-"], "mno-bulk-memory-opt">, Group<m_wasm_Features_Group>;
def mcall_indirect_overlong : Flag<["-"], "mcall-indirect-overlong">, Group<m_wasm_Features_Group>;
def mno_call_indirect_overlong : Flag<["-"], "mno-call-indirect-overlong">, Group<m_wasm_Features_Group>;
def mexception_handing : Flag<["-"], "mexception-handling">, Group<m_wasm_Features_Group>;
def mno_exception_handing : Flag<["-"], "mno-exception-handling">, Group<m_wasm_Features_Group>;
def mextended_const : Flag<["-"], "mextended-const">, Group<m_wasm_Features_Group>;
Expand Down
8 changes: 8 additions & 0 deletions clang/include/clang/Sema/SemaOpenACC.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ class SemaOpenACC : public SemaBase {
/// which allows us to diagnose if the value of 'N' is too large for the
/// current number of 'for' loops.
bool CollapseDepthSatisfied = true;

/// Records the kind of the directive that this clause is attached to, which
/// allows us to use it in diagnostics.
OpenACCDirectiveKind DirectiveKind = OpenACCDirectiveKind::Invalid;
} CollapseInfo;

/// The 'tile' clause requires a bit of additional checking as well, so like
Expand All @@ -103,6 +107,10 @@ class SemaOpenACC : public SemaBase {
/// which allows us to diagnose if the number of arguments is too large for
/// the current number of 'for' loops.
bool TileDepthSatisfied = true;

/// Records the kind of the directive that this clause is attached to, which
/// allows us to use it in diagnostics.
OpenACCDirectiveKind DirectiveKind = OpenACCDirectiveKind::Invalid;
} TileInfo;

/// A list of the active reduction clauses, which allows us to check that all
Expand Down
32 changes: 6 additions & 26 deletions clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -429,47 +429,27 @@ class BranchNodeBuilder: public NodeBuilder {
const CFGBlock *DstT;
const CFGBlock *DstF;

bool InFeasibleTrue;
bool InFeasibleFalse;

void anchor() override;

public:
BranchNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet,
const NodeBuilderContext &C,
const CFGBlock *dstT, const CFGBlock *dstF)
: NodeBuilder(SrcNode, DstSet, C), DstT(dstT), DstF(dstF),
InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {
const NodeBuilderContext &C, const CFGBlock *DT,
const CFGBlock *DF)
: NodeBuilder(SrcNode, DstSet, C), DstT(DT), DstF(DF) {
// The branch node builder does not generate autotransitions.
// If there are no successors it means that both branches are infeasible.
takeNodes(SrcNode);
}

BranchNodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet,
const NodeBuilderContext &C,
const CFGBlock *dstT, const CFGBlock *dstF)
: NodeBuilder(SrcSet, DstSet, C), DstT(dstT), DstF(dstF),
InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {
const NodeBuilderContext &C, const CFGBlock *DT,
const CFGBlock *DF)
: NodeBuilder(SrcSet, DstSet, C), DstT(DT), DstF(DF) {
takeNodes(SrcSet);
}

ExplodedNode *generateNode(ProgramStateRef State, bool branch,
ExplodedNode *Pred);

const CFGBlock *getTargetBlock(bool branch) const {
return branch ? DstT : DstF;
}

void markInfeasible(bool branch) {
if (branch)
InFeasibleTrue = true;
else
InFeasibleFalse = true;
}

bool isFeasible(bool branch) {
return branch ? !InFeasibleTrue : !InFeasibleFalse;
}
};

class IndirectGotoNodeBuilder {
Expand Down
10 changes: 8 additions & 2 deletions clang/lib/AST/ASTDiagnostic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1899,11 +1899,17 @@ class TemplateDiff {

E = E->IgnoreImpCasts();

if (isa<IntegerLiteral>(E)) return false;
auto CheckIntegerLiteral = [](Expr *E) {
if (auto *TemplateExpr = dyn_cast<SubstNonTypeTemplateParmExpr>(E))
E = TemplateExpr->getReplacement();
return isa<IntegerLiteral>(E);
};

if (CheckIntegerLiteral(E)) return false;

if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E))
if (UO->getOpcode() == UO_Minus)
if (isa<IntegerLiteral>(UO->getSubExpr()))
if (CheckIntegerLiteral(UO->getSubExpr()))
return false;

if (isa<CXXBoolLiteralExpr>(E))
Expand Down
16 changes: 14 additions & 2 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6093,8 +6093,7 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
Decl::IDNS_TagFriend))
continue;

Decl *Found = FoundDecl;
auto *FoundTemplate = dyn_cast<ClassTemplateDecl>(Found);
auto *FoundTemplate = dyn_cast<ClassTemplateDecl>(FoundDecl);
if (FoundTemplate) {
if (!hasSameVisibilityContextAndLinkage(FoundTemplate, D))
continue;
Expand All @@ -6118,6 +6117,19 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
// see ASTTests test ImportExistingFriendClassTemplateDef.
continue;
}
// When importing a friend, it is possible that multiple declarations
// with same name can co-exist in specific cases (if a template contains
// a friend template and has a specialization). For this case the
// declarations should match, except that the "template depth" is
// different. No linking of previous declaration is needed in this case.
// FIXME: This condition may need refinement.
if (D->getFriendObjectKind() != Decl::FOK_None &&
FoundTemplate->getFriendObjectKind() != Decl::FOK_None &&
D->getFriendObjectKind() != FoundTemplate->getFriendObjectKind() &&
IsStructuralMatch(D, FoundTemplate, /*Complain=*/false,
/*IgnoreTemplateParmDepth=*/true))
continue;

ConflictingDecls.push_back(FoundDecl);
}
}
Expand Down
16 changes: 12 additions & 4 deletions clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -448,8 +448,8 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {

QualType SubExprTy = SubExpr->getType();
std::optional<PrimType> FromT = classify(SubExprTy);
// Casts from integer to vectors in C.
if (FromT && CE->getType()->isVectorType())
// Casts from integer/vector to vector.
if (CE->getType()->isVectorType())
return this->emitBuiltinBitCast(CE);

std::optional<PrimType> ToT = classify(CE->getType());
Expand Down Expand Up @@ -1000,7 +1000,10 @@ bool Compiler<Emitter>::VisitPointerArithBinOp(const BinaryOperator *E) {
if (!visitAsPointer(RHS, *RT) || !visitAsPointer(LHS, *LT))
return false;

return this->emitSubPtr(classifyPrim(E->getType()), E);
PrimType IntT = classifyPrim(E->getType());
if (!this->emitSubPtr(IntT, E))
return false;
return DiscardResult ? this->emitPop(IntT, E) : true;
}

PrimType OffsetType;
Expand Down Expand Up @@ -5911,6 +5914,9 @@ bool Compiler<Emitter>::VisitVectorUnaryOperator(const UnaryOperator *E) {
return this->discard(SubExpr);

auto UnaryOp = E->getOpcode();
if (UnaryOp == UO_Extension)
return this->delegate(SubExpr);

if (UnaryOp != UO_Plus && UnaryOp != UO_Minus && UnaryOp != UO_LNot &&
UnaryOp != UO_Not && UnaryOp != UO_AddrOf)
return this->emitInvalid(E);
Expand Down Expand Up @@ -6502,7 +6508,7 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) {
// we later assume it to be one (i.e. a PT_Ptr). However,
// we call this function for other utility methods where
// a bitcast might be useful, so convert it to a PT_Ptr in that case.
if (SubExpr->isGLValue()) {
if (SubExpr->isGLValue() || FromType->isVectorType()) {
if (!this->visit(SubExpr))
return false;
} else if (std::optional<PrimType> FromT = classify(SubExpr)) {
Expand All @@ -6514,6 +6520,8 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) {
return false;
if (!this->emitGetPtrLocal(TempOffset, E))
return false;
} else {
return false;
}

if (!ToT || ToT == PT_Ptr) {
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/AST/ByteCode/Integral.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,9 @@ template <unsigned Bits, bool Signed> class Integral final {
APSInt toAPSInt() const {
return APSInt(APInt(Bits, static_cast<uint64_t>(V), Signed), !Signed);
}
APSInt toAPSInt(unsigned BitWidth) const { return APSInt(toAPInt(BitWidth)); }
APSInt toAPSInt(unsigned BitWidth) const {
return APSInt(toAPInt(BitWidth), !Signed);
}
APInt toAPInt(unsigned BitWidth) const {
if constexpr (Signed)
return APInt(Bits, static_cast<uint64_t>(V), Signed)
Expand Down
176 changes: 155 additions & 21 deletions clang/lib/AST/ByteCode/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ template <typename T>
static void pushInteger(InterpState &S, T Val, QualType QT) {
if constexpr (std::is_same_v<T, APInt>)
pushInteger(S, APSInt(Val, !std::is_signed_v<T>), QT);
else if constexpr (std::is_same_v<T, APSInt>)
pushInteger(S, Val, QT);
else
pushInteger(S,
APSInt(APInt(sizeof(T) * 8, static_cast<uint64_t>(Val),
Expand Down Expand Up @@ -146,6 +148,17 @@ static bool retPrimValue(InterpState &S, CodePtr OpPC,
#undef RET_CASE
}

static void diagnoseNonConstexprBuiltin(InterpState &S, CodePtr OpPC,
unsigned ID) {
auto Loc = S.Current->getSource(OpPC);
if (S.getLangOpts().CPlusPlus11)
S.CCEDiag(Loc, diag::note_constexpr_invalid_function)
<< /*isConstexpr=*/0 << /*isConstructor=*/0
<< ("'" + S.getASTContext().BuiltinInfo.getName(ID) + "'").str();
else
S.CCEDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
}

static bool interp__builtin_is_constant_evaluated(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const CallExpr *Call) {
Expand Down Expand Up @@ -179,10 +192,14 @@ static bool interp__builtin_is_constant_evaluated(InterpState &S, CodePtr OpPC,

static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const CallExpr *Call) {
const Function *Func, const CallExpr *Call) {
unsigned ID = Func->getBuiltinID();
const Pointer &A = getParam<Pointer>(Frame, 0);
const Pointer &B = getParam<Pointer>(Frame, 1);

if (ID == Builtin::BIstrcmp)
diagnoseNonConstexprBuiltin(S, OpPC, ID);

if (!CheckLive(S, OpPC, A, AK_Read) || !CheckLive(S, OpPC, B, AK_Read))
return false;

Expand Down Expand Up @@ -222,9 +239,13 @@ static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC,

static bool interp__builtin_strlen(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const CallExpr *Call) {
const Function *Func, const CallExpr *Call) {
unsigned ID = Func->getBuiltinID();
const Pointer &StrPtr = getParam<Pointer>(Frame, 0);

if (ID == Builtin::BIstrlen)
diagnoseNonConstexprBuiltin(S, OpPC, ID);

if (!CheckArray(S, OpPC, StrPtr))
return false;

Expand Down Expand Up @@ -1695,32 +1716,126 @@ static bool interp__builtin_vector_reduce(InterpState &S, CodePtr OpPC,
assert(Arg.getFieldDesc()->isPrimitiveArray());

unsigned ID = Func->getBuiltinID();
if (ID == Builtin::BI__builtin_reduce_add) {
QualType ElemType = Arg.getFieldDesc()->getElemQualType();
assert(Call->getType() == ElemType);
PrimType ElemT = *S.getContext().classify(ElemType);
unsigned NumElems = Arg.getNumElems();

INT_TYPE_SWITCH(ElemT, {
T Sum = Arg.atIndex(0).deref<T>();
unsigned BitWidth = Sum.bitWidth();
for (unsigned I = 1; I != NumElems; ++I) {
T Elem = Arg.atIndex(I).deref<T>();
if (T::add(Sum, Elem, BitWidth, &Sum)) {
QualType ElemType = Arg.getFieldDesc()->getElemQualType();
assert(Call->getType() == ElemType);
PrimType ElemT = *S.getContext().classify(ElemType);
unsigned NumElems = Arg.getNumElems();

INT_TYPE_SWITCH_NO_BOOL(ElemT, {
T Result = Arg.atIndex(0).deref<T>();
unsigned BitWidth = Result.bitWidth();
for (unsigned I = 1; I != NumElems; ++I) {
T Elem = Arg.atIndex(I).deref<T>();
T PrevResult = Result;

if (ID == Builtin::BI__builtin_reduce_add) {
if (T::add(Result, Elem, BitWidth, &Result)) {
unsigned OverflowBits = BitWidth + 1;
(void)handleOverflow(
S, OpPC,
(Sum.toAPSInt(OverflowBits) + Elem.toAPSInt(OverflowBits)));
(void)handleOverflow(S, OpPC,
(PrevResult.toAPSInt(OverflowBits) +
Elem.toAPSInt(OverflowBits)));
return false;
}
} else if (ID == Builtin::BI__builtin_reduce_mul) {
if (T::mul(Result, Elem, BitWidth, &Result)) {
unsigned OverflowBits = BitWidth * 2;
(void)handleOverflow(S, OpPC,
(PrevResult.toAPSInt(OverflowBits) *
Elem.toAPSInt(OverflowBits)));
return false;
}

} else if (ID == Builtin::BI__builtin_reduce_and) {
(void)T::bitAnd(Result, Elem, BitWidth, &Result);
} else if (ID == Builtin::BI__builtin_reduce_or) {
(void)T::bitOr(Result, Elem, BitWidth, &Result);
} else if (ID == Builtin::BI__builtin_reduce_xor) {
(void)T::bitXor(Result, Elem, BitWidth, &Result);
} else {
llvm_unreachable("Unhandled vector reduce builtin");
}
pushInteger(S, Sum, Call->getType());
}
pushInteger(S, Result.toAPSInt(), Call->getType());
});

return true;
}

/// Can be called with an integer or vector as the first and only parameter.
static bool interp__builtin_elementwise_popcount(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func,
const CallExpr *Call) {
assert(Call->getNumArgs() == 1);
if (Call->getArg(0)->getType()->isIntegerType()) {
PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
APSInt Val = peekToAPSInt(S.Stk, ArgT);
pushInteger(S, Val.popcount(), Call->getType());
return true;
}
// Otherwise, the argument must be a vector.
assert(Call->getArg(0)->getType()->isVectorType());
const Pointer &Arg = S.Stk.peek<Pointer>();
assert(Arg.getFieldDesc()->isPrimitiveArray());
const Pointer &Dst = S.Stk.peek<Pointer>(primSize(PT_Ptr) * 2);
assert(Dst.getFieldDesc()->isPrimitiveArray());
assert(Arg.getFieldDesc()->getNumElems() ==
Dst.getFieldDesc()->getNumElems());

QualType ElemType = Arg.getFieldDesc()->getElemQualType();
PrimType ElemT = *S.getContext().classify(ElemType);
unsigned NumElems = Arg.getNumElems();

// FIXME: Reading from uninitialized vector elements?
for (unsigned I = 0; I != NumElems; ++I) {
INT_TYPE_SWITCH_NO_BOOL(ElemT, {
Dst.atIndex(I).deref<T>() =
T::from(Arg.atIndex(I).deref<T>().toAPSInt().popcount());
Dst.atIndex(I).initialize();
});
}

return true;
}
static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func, const CallExpr *Call) {
assert(Call->getNumArgs() == 3);
unsigned ID = Func->getBuiltinID();
Pointer DestPtr = getParam<Pointer>(Frame, 0);
const Pointer &SrcPtr = getParam<Pointer>(Frame, 1);
const APSInt &Size =
peekToAPSInt(S.Stk, *S.getContext().classify(Call->getArg(2)));
assert(!Size.isSigned() && "memcpy and friends take an unsigned size");

if (ID == Builtin::BImemcpy || ID == Builtin::BImemmove)
diagnoseNonConstexprBuiltin(S, OpPC, ID);

bool Move = (ID == Builtin::BI__builtin_memmove || ID == Builtin::BImemmove);

// If the size is zero, we treat this as always being a valid no-op.
if (Size.isZero()) {
S.Stk.push<Pointer>(DestPtr);
return true;
}

llvm_unreachable("Unsupported vector reduce builtin");
if (SrcPtr.isZero() || DestPtr.isZero()) {
Pointer DiagPtr = (SrcPtr.isZero() ? SrcPtr : DestPtr);
S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_memcpy_null)
<< /*IsMove=*/Move << /*IsWchar=*/false << !SrcPtr.isZero()
<< DiagPtr.toDiagnosticString(S.getASTContext());
return false;
}

// As a last resort, reject dummy pointers.
if (DestPtr.isDummy() || SrcPtr.isDummy())
return false;

if (!DoBitCastPtr(S, OpPC, SrcPtr, DestPtr))
return false;

S.Stk.push<Pointer>(DestPtr);
return true;
}

bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
Expand All @@ -1738,11 +1853,13 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
case Builtin::BI__assume:
break;
case Builtin::BI__builtin_strcmp:
if (!interp__builtin_strcmp(S, OpPC, Frame, Call))
case Builtin::BIstrcmp:
if (!interp__builtin_strcmp(S, OpPC, Frame, F, Call))
return false;
break;
case Builtin::BI__builtin_strlen:
if (!interp__builtin_strlen(S, OpPC, Frame, Call))
case Builtin::BIstrlen:
if (!interp__builtin_strlen(S, OpPC, Frame, F, Call))
return false;
break;
case Builtin::BI__builtin_nan:
Expand Down Expand Up @@ -2169,10 +2286,27 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
break;

case Builtin::BI__builtin_reduce_add:
case Builtin::BI__builtin_reduce_mul:
case Builtin::BI__builtin_reduce_and:
case Builtin::BI__builtin_reduce_or:
case Builtin::BI__builtin_reduce_xor:
if (!interp__builtin_vector_reduce(S, OpPC, Frame, F, Call))
return false;
break;

case Builtin::BI__builtin_elementwise_popcount:
if (!interp__builtin_elementwise_popcount(S, OpPC, Frame, F, Call))
return false;
break;

case Builtin::BI__builtin_memcpy:
case Builtin::BImemcpy:
case Builtin::BI__builtin_memmove:
case Builtin::BImemmove:
if (!interp__builtin_memcpy(S, OpPC, Frame, F, Call))
return false;
break;

default:
S.FFDiag(S.Current->getLocation(OpPC),
diag::note_invalid_subexpr_in_const_expr)
Expand Down
18 changes: 12 additions & 6 deletions clang/lib/AST/CXXInheritance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ bool CXXRecordDecl::forallBases(ForallBasesCallback BaseMatches) const {
return false;

CXXRecordDecl *Base =
cast_or_null<CXXRecordDecl>(Ty->getDecl()->getDefinition());
cast_if_present<CXXRecordDecl>(Ty->getDecl()->getDefinition());
if (!Base ||
(Base->isDependentContext() &&
!Base->isCurrentInstantiation(Record))) {
Expand Down Expand Up @@ -169,13 +169,21 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context,
QualType BaseType =
Context.getCanonicalType(BaseSpec.getType()).getUnqualifiedType();

bool isCurrentInstantiation = isa<InjectedClassNameType>(BaseType);
if (!isCurrentInstantiation) {
if (auto *BaseRecord = cast_if_present<CXXRecordDecl>(
BaseSpec.getType()->getAsRecordDecl()))
isCurrentInstantiation = BaseRecord->isDependentContext() &&
BaseRecord->isCurrentInstantiation(Record);
}
// C++ [temp.dep]p3:
// In the definition of a class template or a member of a class template,
// if a base class of the class template depends on a template-parameter,
// the base class scope is not examined during unqualified name lookup
// either at the point of definition of the class template or member or
// during an instantiation of the class tem- plate or member.
if (!LookupInDependent && BaseType->isDependentType())
if (!LookupInDependent &&
(BaseType->isDependentType() && !isCurrentInstantiation))
continue;

// Determine whether we need to visit this base class at all,
Expand Down Expand Up @@ -243,9 +251,8 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context,
return FoundPath;
}
} else if (VisitBase) {
CXXRecordDecl *BaseRecord;
CXXRecordDecl *BaseRecord = nullptr;
if (LookupInDependent) {
BaseRecord = nullptr;
const TemplateSpecializationType *TST =
BaseSpec.getType()->getAs<TemplateSpecializationType>();
if (!TST) {
Expand All @@ -264,8 +271,7 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context,
BaseRecord = nullptr;
}
} else {
BaseRecord = cast<CXXRecordDecl>(
BaseSpec.getType()->castAs<RecordType>()->getDecl());
BaseRecord = cast<CXXRecordDecl>(BaseSpec.getType()->getAsRecordDecl());
}
if (BaseRecord &&
lookupInBases(Context, BaseRecord, BaseMatches, LookupInDependent)) {
Expand Down
2 changes: 0 additions & 2 deletions clang/lib/AST/DeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2602,8 +2602,6 @@ bool CXXMethodDecl::isMoveAssignmentOperator() const {

void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) {
assert(MD->isCanonicalDecl() && "Method is not canonical!");
assert(!MD->getParent()->isDependentContext() &&
"Can't add an overridden method to a class template!");
assert(MD->isVirtual() && "Method is not virtual!");

getASTContext().addOverriddenMethod(this, MD);
Expand Down
21 changes: 16 additions & 5 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11310,7 +11310,8 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
switch (E->getBuiltinCallee()) {
default:
return false;
case Builtin::BI__builtin_elementwise_popcount: {
case Builtin::BI__builtin_elementwise_popcount:
case Builtin::BI__builtin_elementwise_bitreverse: {
APValue Source;
if (!EvaluateAsRValue(Info, E->getArg(0), Source))
return false;
Expand All @@ -11322,9 +11323,18 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {

for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) {
APSInt Elt = Source.getVectorElt(EltNum).getInt();
ResultElements.push_back(
APValue(APSInt(APInt(Info.Ctx.getIntWidth(DestEltTy), Elt.popcount()),
DestEltTy->isUnsignedIntegerOrEnumerationType())));
switch (E->getBuiltinCallee()) {
case Builtin::BI__builtin_elementwise_popcount:
ResultElements.push_back(APValue(
APSInt(APInt(Info.Ctx.getIntWidth(DestEltTy), Elt.popcount()),
DestEltTy->isUnsignedIntegerOrEnumerationType())));
break;
case Builtin::BI__builtin_elementwise_bitreverse:
ResultElements.push_back(
APValue(APSInt(Elt.reverseBits(),
DestEltTy->isUnsignedIntegerOrEnumerationType())));
break;
}
}

return Success(APValue(ResultElements.data(), ResultElements.size()), E);
Expand Down Expand Up @@ -12833,7 +12843,8 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
case Builtin::BI__builtin_bitreverse8:
case Builtin::BI__builtin_bitreverse16:
case Builtin::BI__builtin_bitreverse32:
case Builtin::BI__builtin_bitreverse64: {
case Builtin::BI__builtin_bitreverse64:
case Builtin::BI__builtin_elementwise_bitreverse: {
APSInt Val;
if (!EvaluateInteger(E->getArg(0), Val, Info))
return false;
Expand Down
71 changes: 71 additions & 0 deletions clang/lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,7 @@ class CXXNameMangler {
static StringRef getCallingConvQualifierName(CallingConv CC);
void mangleExtParameterInfo(FunctionProtoType::ExtParameterInfo info);
void mangleExtFunctionInfo(const FunctionType *T);
void mangleSMEAttrs(unsigned SMEAttrs);
void mangleBareFunctionType(const FunctionProtoType *T, bool MangleReturnType,
const FunctionDecl *FD = nullptr);
void mangleNeonVectorType(const VectorType *T);
Expand Down Expand Up @@ -3532,6 +3533,69 @@ void CXXNameMangler::mangleExtFunctionInfo(const FunctionType *T) {
// FIXME: noreturn
}

enum class AAPCSBitmaskSME : unsigned {
ArmStreamingBit = 1 << 0,
ArmStreamingCompatibleBit = 1 << 1,
ArmAgnosticSMEZAStateBit = 1 << 2,
ZA_Shift = 3,
ZT0_Shift = 6,
NoState = 0b000,
ArmIn = 0b001,
ArmOut = 0b010,
ArmInOut = 0b011,
ArmPreserves = 0b100,
LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/ArmPreserves << ZT0_Shift)
};

static AAPCSBitmaskSME encodeAAPCSZAState(unsigned SMEAttrs) {
switch (SMEAttrs) {
case FunctionType::ARM_None:
return AAPCSBitmaskSME::NoState;
case FunctionType::ARM_In:
return AAPCSBitmaskSME::ArmIn;
case FunctionType::ARM_Out:
return AAPCSBitmaskSME::ArmOut;
case FunctionType::ARM_InOut:
return AAPCSBitmaskSME::ArmInOut;
case FunctionType::ARM_Preserves:
return AAPCSBitmaskSME::ArmPreserves;
default:
llvm_unreachable("Unrecognised SME attribute");
}
}

// The mangling scheme for function types which have SME attributes is
// implemented as a "pseudo" template:
//
// '__SME_ATTRS<<normal_function_type>, <sme_state>>'
//
// Combining the function type with a bitmask representing the streaming and ZA
// properties of the function's interface.
//
// Mangling of SME keywords is described in more detail in the AArch64 ACLE:
// https://github.com/ARM-software/acle/blob/main/main/acle.md#c-mangling-of-sme-keywords
//
void CXXNameMangler::mangleSMEAttrs(unsigned SMEAttrs) {
if (!SMEAttrs)
return;

AAPCSBitmaskSME Bitmask = AAPCSBitmaskSME(0);
if (SMEAttrs & FunctionType::SME_PStateSMEnabledMask)
Bitmask |= AAPCSBitmaskSME::ArmStreamingBit;
else if (SMEAttrs & FunctionType::SME_PStateSMCompatibleMask)
Bitmask |= AAPCSBitmaskSME::ArmStreamingCompatibleBit;

// TODO: Must represent __arm_agnostic("sme_za_state")

Bitmask |= encodeAAPCSZAState(FunctionType::getArmZAState(SMEAttrs))
<< AAPCSBitmaskSME::ZA_Shift;

Bitmask |= encodeAAPCSZAState(FunctionType::getArmZT0State(SMEAttrs))
<< AAPCSBitmaskSME::ZT0_Shift;

Out << "Lj" << static_cast<unsigned>(Bitmask) << "EE";
}

void
CXXNameMangler::mangleExtParameterInfo(FunctionProtoType::ExtParameterInfo PI) {
// Vendor-specific qualifiers are emitted in reverse alphabetical order.
Expand Down Expand Up @@ -3569,6 +3633,11 @@ CXXNameMangler::mangleExtParameterInfo(FunctionProtoType::ExtParameterInfo PI) {
// <function-type> ::= [<CV-qualifiers>] F [Y]
// <bare-function-type> [<ref-qualifier>] E
void CXXNameMangler::mangleType(const FunctionProtoType *T) {
unsigned SMEAttrs = T->getAArch64SMEAttributes();

if (SMEAttrs)
Out << "11__SME_ATTRSI";

mangleExtFunctionInfo(T);

// Mangle CV-qualifiers, if present. These are 'this' qualifiers,
Expand Down Expand Up @@ -3603,6 +3672,8 @@ void CXXNameMangler::mangleType(const FunctionProtoType *T) {
mangleRefQualifier(T->getRefQualifier());

Out << 'E';

mangleSMEAttrs(SMEAttrs);
}

void CXXNameMangler::mangleType(const FunctionNoProtoType *T) {
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4723,7 +4723,9 @@ LinkageInfo LinkageComputer::computeTypeLinkageInfo(const Type *T) {
case Type::Pipe:
return computeTypeLinkageInfo(cast<PipeType>(T)->getElementType());
case Type::HLSLAttributedResource:
llvm_unreachable("not yet implemented");
return computeTypeLinkageInfo(cast<HLSLAttributedResourceType>(T)
->getContainedType()
->getCanonicalTypeInternal());
}

llvm_unreachable("unhandled type class");
Expand Down
32 changes: 25 additions & 7 deletions clang/lib/ASTMatchers/ASTMatchersInternal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "clang/Basic/LLVM.h"
#include "clang/Lex/Lexer.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
Expand Down Expand Up @@ -697,27 +698,42 @@ static bool isTokenAtLoc(const SourceManager &SM, const LangOptions &LangOpts,
return !Invalid && Text == TokenText;
}

std::optional<SourceLocation>
getExpansionLocOfMacro(StringRef MacroName, SourceLocation Loc,
const ASTContext &Context) {
static std::optional<SourceLocation> getExpansionLocOfMacroRecursive(
StringRef MacroName, SourceLocation Loc, const ASTContext &Context,
llvm::DenseSet<SourceLocation> &CheckedLocations) {
auto &SM = Context.getSourceManager();
const LangOptions &LangOpts = Context.getLangOpts();
while (Loc.isMacroID()) {
if (CheckedLocations.count(Loc))
return std::nullopt;
CheckedLocations.insert(Loc);
SrcMgr::ExpansionInfo Expansion =
SM.getSLocEntry(SM.getFileID(Loc)).getExpansion();
if (Expansion.isMacroArgExpansion())
if (Expansion.isMacroArgExpansion()) {
// Check macro argument for an expansion of the given macro. For example,
// `F(G(3))`, where `MacroName` is `G`.
if (std::optional<SourceLocation> ArgLoc = getExpansionLocOfMacro(
MacroName, Expansion.getSpellingLoc(), Context))
if (std::optional<SourceLocation> ArgLoc =
getExpansionLocOfMacroRecursive(MacroName,
Expansion.getSpellingLoc(),
Context, CheckedLocations)) {
return ArgLoc;
}
}
Loc = Expansion.getExpansionLocStart();
if (isTokenAtLoc(SM, LangOpts, MacroName, Loc))
return Loc;
}
return std::nullopt;
}

std::optional<SourceLocation>
getExpansionLocOfMacro(StringRef MacroName, SourceLocation Loc,
const ASTContext &Context) {
llvm::DenseSet<SourceLocation> CheckedLocations;
return getExpansionLocOfMacroRecursive(MacroName, Loc, Context,
CheckedLocations);
}

std::shared_ptr<llvm::Regex> createAndVerifyRegex(StringRef Regex,
llvm::Regex::RegexFlags Flags,
StringRef MatcherID) {
Expand Down Expand Up @@ -799,6 +815,7 @@ const internal::VariadicDynCastAllOfMatcher<TypeLoc, ElaboratedTypeLoc>

const internal::VariadicDynCastAllOfMatcher<Stmt, UnaryExprOrTypeTraitExpr>
unaryExprOrTypeTraitExpr;
const internal::VariadicDynCastAllOfMatcher<Decl, ExportDecl> exportDecl;
const internal::VariadicDynCastAllOfMatcher<Decl, ValueDecl> valueDecl;
const internal::VariadicDynCastAllOfMatcher<Decl, CXXConstructorDecl>
cxxConstructorDecl;
Expand Down Expand Up @@ -1097,7 +1114,8 @@ AST_TYPELOC_TRAVERSE_MATCHER_DEF(hasValueType,
AST_TYPELOC_TRAVERSE_MATCHER_DEF(
pointee,
AST_POLYMORPHIC_SUPPORTED_TYPES(BlockPointerType, MemberPointerType,
PointerType, ReferenceType));
PointerType, ReferenceType,
ObjCObjectPointerType));

const internal::VariadicDynCastAllOfMatcher<Stmt, OMPExecutableDirective>
ompExecutableDirective;
Expand Down
34 changes: 34 additions & 0 deletions clang/lib/Basic/Targets/WebAssembly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ bool WebAssemblyTargetInfo::hasFeature(StringRef Feature) const {
return llvm::StringSwitch<bool>(Feature)
.Case("atomics", HasAtomics)
.Case("bulk-memory", HasBulkMemory)
.Case("bulk-memory-opt", HasBulkMemoryOpt)
.Case("call-indirect-overlong", HasCallIndirectOverlong)
.Case("exception-handling", HasExceptionHandling)
.Case("extended-const", HasExtendedConst)
.Case("fp16", HasFP16)
Expand Down Expand Up @@ -79,6 +81,8 @@ void WebAssemblyTargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__wasm_atomics__");
if (HasBulkMemory)
Builder.defineMacro("__wasm_bulk_memory__");
if (HasBulkMemoryOpt)
Builder.defineMacro("__wasm_bulk_memory_opt__");
if (HasExceptionHandling)
Builder.defineMacro("__wasm_exception_handling__");
if (HasExtendedConst)
Expand Down Expand Up @@ -155,6 +159,8 @@ bool WebAssemblyTargetInfo::initFeatureMap(
const std::vector<std::string> &FeaturesVec) const {
auto addGenericFeatures = [&]() {
Features["bulk-memory"] = true;
Features["bulk-memory-opt"] = true;
Features["call-indirect-overlong"] = true;
Features["multivalue"] = true;
Features["mutable-globals"] = true;
Features["nontrapping-fptoint"] = true;
Expand Down Expand Up @@ -200,6 +206,22 @@ bool WebAssemblyTargetInfo::handleTargetFeatures(
HasBulkMemory = false;
continue;
}
if (Feature == "+bulk-memory-opt") {
HasBulkMemoryOpt = true;
continue;
}
if (Feature == "-bulk-memory-opt") {
HasBulkMemoryOpt = false;
continue;
}
if (Feature == "+call-indirect-overlong") {
HasCallIndirectOverlong = true;
continue;
}
if (Feature == "-call-indirect-overlong") {
HasCallIndirectOverlong = false;
continue;
}
if (Feature == "+exception-handling") {
HasExceptionHandling = true;
continue;
Expand Down Expand Up @@ -310,6 +332,18 @@ bool WebAssemblyTargetInfo::handleTargetFeatures(
<< Feature << "-target-feature";
return false;
}

// bulk-memory-opt is a subset of bulk-memory.
if (HasBulkMemory) {
HasBulkMemoryOpt = true;
}

// The reference-types feature included the change to `call_indirect`
// encodings to support overlong immediates.
if (HasReferenceTypes) {
HasCallIndirectOverlong = true;
}

return true;
}

Expand Down
42 changes: 22 additions & 20 deletions clang/lib/Basic/Targets/WebAssembly.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,26 @@ namespace clang {
namespace targets {

static const unsigned WebAssemblyAddrSpaceMap[] = {
0, // Default
0, // opencl_global
0, // opencl_local
0, // opencl_constant
0, // opencl_private
0, // opencl_generic
0, // opencl_global_device
0, // opencl_global_host
0, // cuda_device
0, // cuda_constant
0, // cuda_shared
0, // sycl_global
0, // sycl_global_device
0, // sycl_global_host
0, // sycl_local
0, // sycl_private
0, // ptr32_sptr
0, // ptr32_uptr
0, // ptr64
0, // hlsl_groupshared
0, // Default
0, // opencl_global
0, // opencl_local
0, // opencl_constant
0, // opencl_private
0, // opencl_generic
0, // opencl_global_device
0, // opencl_global_host
0, // cuda_device
0, // cuda_constant
0, // cuda_shared
0, // sycl_global
0, // sycl_global_device
0, // sycl_global_host
0, // sycl_local
0, // sycl_private
0, // ptr32_sptr
0, // ptr32_uptr
0, // ptr64
0, // hlsl_groupshared
20, // wasm_funcref
};

Expand All @@ -55,6 +55,8 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo {

bool HasAtomics = false;
bool HasBulkMemory = false;
bool HasBulkMemoryOpt = false;
bool HasCallIndirectOverlong = false;
bool HasExceptionHandling = false;
bool HasExtendedConst = false;
bool HasFP16 = false;
Expand Down
3 changes: 0 additions & 3 deletions clang/lib/CIR/FrontendAction/CIRGenAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,6 @@ class CIRGenConsumer : public clang::ASTConsumer {
MlirModule->print(*OutputStream, Flags);
}
break;
default:
llvm_unreachable("NYI: CIRGenAction other than EmitCIR");
break;
}
}
};
Expand Down
20 changes: 20 additions & 0 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19060,6 +19060,16 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
return nullptr;

switch (BuiltinID) {
case Builtin::BI__builtin_hlsl_resource_getpointer: {
Value *HandleOp = EmitScalarExpr(E->getArg(0));
Value *IndexOp = EmitScalarExpr(E->getArg(1));

// TODO: Map to an hlsl_device address space.
llvm::Type *RetTy = llvm::PointerType::getUnqual(getLLVMContext());

return Builder.CreateIntrinsic(RetTy, Intrinsic::dx_resource_getpointer,
ArrayRef<Value *>{HandleOp, IndexOp});
}
case Builtin::BI__builtin_hlsl_all: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
return Builder.CreateIntrinsic(
Expand Down Expand Up @@ -19446,6 +19456,12 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: {
assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
"clip operands types mismatch");
return handleHlslClip(E, this);
case Builtin::BI__builtin_hlsl_group_memory_barrier_with_group_sync: {
Intrinsic::ID ID =
CGM.getHLSLRuntime().getGroupMemoryBarrierWithGroupSyncIntrinsic();
return EmitRuntimeCall(
Intrinsic::getOrInsertDeclaration(&CGM.getModule(), ID));
}
}
return nullptr;
}
Expand Down Expand Up @@ -19726,6 +19742,8 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID,
case AMDGPU::BI__builtin_amdgcn_ds_read_tr4_b64_v2i32:
case AMDGPU::BI__builtin_amdgcn_ds_read_tr8_b64_v2i32:
case AMDGPU::BI__builtin_amdgcn_ds_read_tr6_b96_v3i32:
case AMDGPU::BI__builtin_amdgcn_ds_read_tr16_b64_v4f16:
case AMDGPU::BI__builtin_amdgcn_ds_read_tr16_b64_v4bf16:
case AMDGPU::BI__builtin_amdgcn_ds_read_tr16_b64_v4i16: {
Intrinsic::ID IID;
switch (BuiltinID) {
Expand All @@ -19751,6 +19769,8 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID,
IID = Intrinsic::amdgcn_ds_read_tr6_b96;
break;
case AMDGPU::BI__builtin_amdgcn_ds_read_tr16_b64_v4i16:
case AMDGPU::BI__builtin_amdgcn_ds_read_tr16_b64_v4f16:
case AMDGPU::BI__builtin_amdgcn_ds_read_tr16_b64_v4bf16:
IID = Intrinsic::amdgcn_ds_read_tr16_b64;
break;
}
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1314,10 +1314,10 @@ static llvm::Value *CreateCoercedLoad(Address Src, llvm::Type *Ty,
}
if (ScalableDstTy->getElementType() == FixedSrcTy->getElementType()) {
auto *Load = CGF.Builder.CreateLoad(Src);
auto *UndefVec = llvm::UndefValue::get(ScalableDstTy);
auto *PoisonVec = llvm::PoisonValue::get(ScalableDstTy);
auto *Zero = llvm::Constant::getNullValue(CGF.CGM.Int64Ty);
llvm::Value *Result = CGF.Builder.CreateInsertVector(
ScalableDstTy, UndefVec, Load, Zero, "cast.scalable");
ScalableDstTy, PoisonVec, Load, Zero, "cast.scalable");
if (ScalableDstTy != Ty)
Result = CGF.Builder.CreateBitCast(Result, Ty);
return Result;
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CGHLSLRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ class CGHLSLRuntime {

GENERATE_HLSL_INTRINSIC_FUNCTION(CreateHandleFromBinding, handle_fromBinding)
GENERATE_HLSL_INTRINSIC_FUNCTION(BufferUpdateCounter, bufferUpdateCounter)
GENERATE_HLSL_INTRINSIC_FUNCTION(GroupMemoryBarrierWithGroupSync,
group_memory_barrier_with_group_sync)

//===----------------------------------------------------------------------===//
// End of reserved area for HLSL intrinsic getters.
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,8 @@ static bool checkAliasedGlobal(
// mangled name.
for (const auto &[Decl, Name] : MangledDeclNames) {
if (const auto *ND = dyn_cast<NamedDecl>(Decl.getDecl())) {
if (ND->getName() == GV->getName()) {
IdentifierInfo *II = ND->getIdentifier();
if (II && II->getName() == GV->getName()) {
Diags.Report(Location, diag::note_alias_mangled_name_alternative)
<< Name
<< FixItHint::CreateReplacement(
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1348,6 +1348,7 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) {
case llvm::Triple::riscv64:
case llvm::Triple::systemz:
case llvm::Triple::xcore:
case llvm::Triple::xtensa:
return false;
}
}
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Driver/ToolChains/Flang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -777,6 +777,13 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,

addFortranDialectOptions(Args, CmdArgs);

// 'flang -E' always produces output that is suitable for use as fixed form
// Fortran. However it is only valid free form source if the original is also
// free form.
if (InputType == types::TY_PP_Fortran &&
!Args.getLastArg(options::OPT_ffixed_form, options::OPT_ffree_form))
CmdArgs.push_back("-ffixed-form");

handleColorDiagnosticsArgs(D, Args, CmdArgs);

// LTO mode is parsed by the Clang driver library.
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Format/Format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3950,6 +3950,7 @@ static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) {
return FormatStyle::LK_Java;
if (FileName.ends_with_insensitive(".js") ||
FileName.ends_with_insensitive(".mjs") ||
FileName.ends_with_insensitive(".cjs") ||
FileName.ends_with_insensitive(".ts")) {
return FormatStyle::LK_JavaScript; // (module) JavaScript or TypeScript.
}
Expand Down
12 changes: 12 additions & 0 deletions clang/lib/Headers/hlsl/hlsl_intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -2481,5 +2481,17 @@ float3 radians(float3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_radians)
float4 radians(float4);

//===----------------------------------------------------------------------===//
// GroupMemoryBarrierWithGroupSync builtins
//===----------------------------------------------------------------------===//

/// \fn void GroupMemoryBarrierWithGroupSync(void)
/// \brief Blocks execution of all threads in a group until all group shared
/// accesses have been completed and all threads in the group have reached this
/// call.

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_group_memory_barrier_with_group_sync)
void GroupMemoryBarrierWithGroupSync(void);

} // namespace hlsl
#endif //_HLSL_HLSL_INTRINSICS_H_
8 changes: 8 additions & 0 deletions clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8119,6 +8119,14 @@ void Parser::ParseParameterDeclarationClause(
}

if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) {
if (getLangOpts().CPlusPlus26) {
// C++26 [dcl.dcl.fct]p3:
// A parameter-declaration-clause of the form
// parameter-list '...' is deprecated.
Diag(EllipsisLoc, diag::warn_deprecated_missing_comma_before_ellipsis)
<< FixItHint::CreateInsertion(EllipsisLoc, ", ");
}

if (!getLangOpts().CPlusPlus) {
// We have ellipsis without a preceding ',', which is ill-formed
// in C. Complain and provide the fix.
Expand Down
188 changes: 87 additions & 101 deletions clang/lib/Sema/HLSLExternalSemaSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,8 @@ struct BuiltinTypeDeclBuilder {
assert(!Record->isCompleteDefinition() && "record is already complete");

ASTContext &Ctx = SemaRef.getASTContext();
TypeSourceInfo *ElementTypeInfo = nullptr;

QualType ElemTy = Ctx.Char8Ty;
if (Template)
ElemTy = getFirstTemplateTypeParam();
ElementTypeInfo = Ctx.getTrivialTypeSourceInfo(ElemTy, SourceLocation());
TypeSourceInfo *ElementTypeInfo =
Ctx.getTrivialTypeSourceInfo(getHandleElementType(), SourceLocation());

// add handle member with resource type attributes
QualType AttributedResTy = QualType();
Expand Down Expand Up @@ -171,80 +167,12 @@ struct BuiltinTypeDeclBuilder {
}

BuiltinTypeDeclBuilder &addArraySubscriptOperators() {
addArraySubscriptOperator(true);
addArraySubscriptOperator(false);
return *this;
}

BuiltinTypeDeclBuilder &addArraySubscriptOperator(bool IsConst) {
assert(!Record->isCompleteDefinition() && "record is already complete");

ASTContext &AST = Record->getASTContext();
QualType ElemTy = AST.Char8Ty;
if (Template)
ElemTy = getFirstTemplateTypeParam();
QualType ReturnTy = ElemTy;

FunctionProtoType::ExtProtoInfo ExtInfo;

// Subscript operators return references to elements, const makes the
// reference and method const so that the underlying data is not mutable.
if (IsConst) {
ExtInfo.TypeQuals.addConst();
ReturnTy.addConst();
}
ReturnTy = AST.getLValueReferenceType(ReturnTy);

QualType MethodTy =
AST.getFunctionType(ReturnTy, {AST.UnsignedIntTy}, ExtInfo);
auto *TSInfo = AST.getTrivialTypeSourceInfo(MethodTy, SourceLocation());
auto *MethodDecl = CXXMethodDecl::Create(
AST, Record, SourceLocation(),
DeclarationNameInfo(
AST.DeclarationNames.getCXXOperatorName(OO_Subscript),
SourceLocation()),
MethodTy, TSInfo, SC_None, false, false, ConstexprSpecKind::Unspecified,
SourceLocation());

IdentifierInfo &II = AST.Idents.get("Idx", tok::TokenKind::identifier);
auto *IdxParam = ParmVarDecl::Create(
AST, MethodDecl->getDeclContext(), SourceLocation(), SourceLocation(),
&II, AST.UnsignedIntTy,
AST.getTrivialTypeSourceInfo(AST.UnsignedIntTy, SourceLocation()),
SC_None, nullptr);
MethodDecl->setParams({IdxParam});

// Also add the parameter to the function prototype.
auto FnProtoLoc = TSInfo->getTypeLoc().getAs<FunctionProtoTypeLoc>();
FnProtoLoc.setParam(0, IdxParam);

// FIXME: Placeholder to make sure we return the correct type - create
// field of element_type and return reference to it. This field will go
// away once indexing into resources is properly implemented in
// llvm/llvm-project#95956.
if (Fields.count("e") == 0) {
addMemberVariable("e", ElemTy, {});
}
FieldDecl *ElemFieldDecl = Fields["e"];

auto *This =
CXXThisExpr::Create(AST, SourceLocation(),
MethodDecl->getFunctionObjectParameterType(), true);
Expr *ElemField = MemberExpr::CreateImplicit(
AST, This, false, ElemFieldDecl, ElemFieldDecl->getType(), VK_LValue,
OK_Ordinary);
auto *Return =
ReturnStmt::Create(AST, SourceLocation(), ElemField, nullptr);

MethodDecl->setBody(CompoundStmt::Create(AST, {Return}, FPOptionsOverride(),
SourceLocation(),
SourceLocation()));
MethodDecl->setLexicalDeclContext(Record);
MethodDecl->setAccess(AccessSpecifier::AS_public);
MethodDecl->addAttr(AlwaysInlineAttr::CreateImplicit(
AST, SourceRange(), AlwaysInlineAttr::CXX11_clang_always_inline));
Record->addDecl(MethodDecl);
DeclarationName Subscript =
AST.DeclarationNames.getCXXOperatorName(OO_Subscript);

addHandleAccessFunction(Subscript, /*IsConst=*/true, /*IsRef=*/true);
addHandleAccessFunction(Subscript, /*IsConst=*/false, /*IsRef=*/true);
return *this;
}

Expand All @@ -265,6 +193,13 @@ struct BuiltinTypeDeclBuilder {
return QualType();
}

QualType getHandleElementType() {
if (Template)
return getFirstTemplateTypeParam();
// TODO: Should we default to VoidTy? Using `i8` is arguably ambiguous.
return SemaRef.getASTContext().Char8Ty;
}

BuiltinTypeDeclBuilder &startDefinition() {
assert(!Record->isCompleteDefinition() && "record is already complete");
Record->startDefinition();
Expand Down Expand Up @@ -294,6 +229,8 @@ struct BuiltinTypeDeclBuilder {
// Builtin types methods
BuiltinTypeDeclBuilder &addIncrementCounterMethod();
BuiltinTypeDeclBuilder &addDecrementCounterMethod();
BuiltinTypeDeclBuilder &addHandleAccessFunction(DeclarationName &Name,
bool IsConst, bool IsRef);
};

struct TemplateParameterListBuilder {
Expand Down Expand Up @@ -453,7 +390,7 @@ struct TemplateParameterListBuilder {
// Builder for methods of builtin types. Allows adding methods to builtin types
// using the builder pattern like this:
//
// BuiltinTypeMethodBuilder(Sema, RecordBuilder, "MethodName", ReturnType)
// BuiltinTypeMethodBuilder(RecordBuilder, "MethodName", ReturnType)
// .addParam("param_name", Type, InOutModifier)
// .callBuiltin("builtin_name", BuiltinParams...)
// .finalizeMethod();
Expand Down Expand Up @@ -486,6 +423,7 @@ struct BuiltinTypeMethodBuilder {
DeclarationNameInfo NameInfo;
QualType ReturnTy;
CXXMethodDecl *Method;
bool IsConst;
llvm::SmallVector<MethodParam> Params;
llvm::SmallVector<Stmt *> StmtsList;

Expand All @@ -508,11 +446,16 @@ struct BuiltinTypeMethodBuilder {
Expr *convertPlaceholder(Expr *E) { return E; }

public:
BuiltinTypeMethodBuilder(Sema &S, BuiltinTypeDeclBuilder &DB, StringRef Name,
QualType ReturnTy)
: DeclBuilder(DB), ReturnTy(ReturnTy), Method(nullptr) {
BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, DeclarationName &Name,
QualType ReturnTy, bool IsConst = false)
: DeclBuilder(DB), NameInfo(DeclarationNameInfo(Name, SourceLocation())),
ReturnTy(ReturnTy), Method(nullptr), IsConst(IsConst) {}

BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, StringRef Name,
QualType ReturnTy, bool IsConst = false)
: DeclBuilder(DB), ReturnTy(ReturnTy), Method(nullptr), IsConst(IsConst) {
const IdentifierInfo &II =
S.getASTContext().Idents.get(Name, tok::TokenKind::identifier);
DB.SemaRef.getASTContext().Idents.get(Name, tok::TokenKind::identifier);
NameInfo = DeclarationNameInfo(DeclarationName(&II), SourceLocation());
}

Expand All @@ -535,8 +478,12 @@ struct BuiltinTypeMethodBuilder {
SmallVector<QualType> ParamTypes;
for (MethodParam &MP : Params)
ParamTypes.emplace_back(MP.Ty);
QualType MethodTy = AST.getFunctionType(ReturnTy, ParamTypes,
FunctionProtoType::ExtProtoInfo());

FunctionProtoType::ExtProtoInfo ExtInfo;
if (IsConst)
ExtInfo.TypeQuals.addConst();

QualType MethodTy = AST.getFunctionType(ReturnTy, ParamTypes, ExtInfo);

// create method decl
auto *TSInfo = AST.getTrivialTypeSourceInfo(MethodTy, SourceLocation());
Expand Down Expand Up @@ -586,7 +533,8 @@ struct BuiltinTypeMethodBuilder {
}

template <typename... Ts>
BuiltinTypeMethodBuilder &callBuiltin(StringRef BuiltinName, Ts... ArgSpecs) {
BuiltinTypeMethodBuilder &callBuiltin(StringRef BuiltinName,
QualType ReturnType, Ts... ArgSpecs) {
std::array<Expr *, sizeof...(ArgSpecs)> Args{
convertPlaceholder(std::forward<Ts>(ArgSpecs))...};

Expand All @@ -599,15 +547,32 @@ struct BuiltinTypeMethodBuilder {
FunctionDecl *FD = lookupBuiltinFunction(DeclBuilder.SemaRef, BuiltinName);
DeclRefExpr *DRE = DeclRefExpr::Create(
AST, NestedNameSpecifierLoc(), SourceLocation(), FD, false,
FD->getNameInfo(), FD->getType(), VK_PRValue);
FD->getNameInfo(), AST.BuiltinFnTy, VK_PRValue);

if (ReturnType.isNull())
ReturnType = FD->getReturnType();

Expr *Call =
CallExpr::Create(AST, DRE, Args, FD->getReturnType(), VK_PRValue,
SourceLocation(), FPOptionsOverride());
Expr *Call = CallExpr::Create(AST, DRE, Args, ReturnType, VK_PRValue,
SourceLocation(), FPOptionsOverride());
StmtsList.push_back(Call);
return *this;
}

BuiltinTypeMethodBuilder &dereference() {
assert(!StmtsList.empty() && "Nothing to dereference");
ASTContext &AST = DeclBuilder.SemaRef.getASTContext();

Expr *LastExpr = dyn_cast<Expr>(StmtsList.back());
assert(LastExpr && "No expression to dereference");
Expr *Deref = UnaryOperator::Create(
AST, LastExpr, UO_Deref, LastExpr->getType()->getPointeeType(),
VK_PRValue, OK_Ordinary, SourceLocation(),
/*CanOverflow=*/false, FPOptionsOverride());
StmtsList.pop_back();
StmtsList.push_back(Deref);
return *this;
}

BuiltinTypeDeclBuilder &finalizeMethod() {
assert(!DeclBuilder.Record->isCompleteDefinition() &&
"record is already complete");
Expand All @@ -621,11 +586,8 @@ struct BuiltinTypeMethodBuilder {
"nothing to return from non-void method");
if (ReturnTy != AST.VoidTy) {
if (Expr *LastExpr = dyn_cast<Expr>(StmtsList.back())) {
assert(AST.hasSameUnqualifiedType(
isa<CallExpr>(LastExpr)
? cast<CallExpr>(LastExpr)->getCallReturnType(AST)
: LastExpr->getType(),
ReturnTy) &&
assert(AST.hasSameUnqualifiedType(LastExpr->getType(),
ReturnTy.getNonReferenceType()) &&
"Return type of the last statement must match the return type "
"of the method");
if (!isa<ReturnStmt>(LastExpr)) {
Expand Down Expand Up @@ -672,19 +634,43 @@ BuiltinTypeDeclBuilder::addSimpleTemplateParams(ArrayRef<StringRef> Names,

BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addIncrementCounterMethod() {
using PH = BuiltinTypeMethodBuilder::PlaceHolder;
return BuiltinTypeMethodBuilder(SemaRef, *this, "IncrementCounter",
return BuiltinTypeMethodBuilder(*this, "IncrementCounter",
SemaRef.getASTContext().UnsignedIntTy)
.callBuiltin("__builtin_hlsl_buffer_update_counter", PH::Handle,
getConstantIntExpr(1))
.callBuiltin("__builtin_hlsl_buffer_update_counter", QualType(),
PH::Handle, getConstantIntExpr(1))
.finalizeMethod();
}

BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDecrementCounterMethod() {
using PH = BuiltinTypeMethodBuilder::PlaceHolder;
return BuiltinTypeMethodBuilder(SemaRef, *this, "DecrementCounter",
return BuiltinTypeMethodBuilder(*this, "DecrementCounter",
SemaRef.getASTContext().UnsignedIntTy)
.callBuiltin("__builtin_hlsl_buffer_update_counter", PH::Handle,
getConstantIntExpr(-1))
.callBuiltin("__builtin_hlsl_buffer_update_counter", QualType(),
PH::Handle, getConstantIntExpr(-1))
.finalizeMethod();
}

BuiltinTypeDeclBuilder &
BuiltinTypeDeclBuilder::addHandleAccessFunction(DeclarationName &Name,
bool IsConst, bool IsRef) {
assert(!Record->isCompleteDefinition() && "record is already complete");
ASTContext &AST = SemaRef.getASTContext();
using PH = BuiltinTypeMethodBuilder::PlaceHolder;

QualType ElemTy = getHandleElementType();
// TODO: Map to an hlsl_device address space.
QualType ElemPtrTy = AST.getPointerType(ElemTy);
QualType ReturnTy = ElemTy;
if (IsConst)
ReturnTy.addConst();
if (IsRef)
ReturnTy = AST.getLValueReferenceType(ReturnTy);

return BuiltinTypeMethodBuilder(*this, Name, ReturnTy, IsConst)
.addParam("Index", AST.UnsignedIntTy)
.callBuiltin("__builtin_hlsl_resource_getpointer", ElemPtrTy, PH::Handle,
PH::_0)
.dereference()
.finalizeMethod();
}

Expand Down
58 changes: 36 additions & 22 deletions clang/lib/Sema/SemaAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -270,34 +270,48 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
}

void Sema::inferLifetimeCaptureByAttribute(FunctionDecl *FD) {
if (!FD)
auto *MD = dyn_cast_if_present<CXXMethodDecl>(FD);
if (!MD || !MD->getParent()->isInStdNamespace())
return;
auto *MD = dyn_cast<CXXMethodDecl>(FD);
if (!MD || !MD->getIdentifier() || !MD->getParent()->isInStdNamespace())
auto Annotate = [this](const FunctionDecl *MD) {
// Do not infer if any parameter is explicitly annotated.
for (ParmVarDecl *PVD : MD->parameters())
if (PVD->hasAttr<LifetimeCaptureByAttr>())
return;
for (ParmVarDecl *PVD : MD->parameters()) {
// Methods in standard containers that capture values typically accept
// reference-type parameters, e.g., `void push_back(const T& value)`.
// We only apply the lifetime_capture_by attribute to parameters of
// pointer-like reference types (`const T&`, `T&&`).
if (PVD->getType()->isReferenceType() &&
sema::isPointerLikeType(PVD->getType().getNonReferenceType())) {
int CaptureByThis[] = {LifetimeCaptureByAttr::THIS};
PVD->addAttr(
LifetimeCaptureByAttr::CreateImplicit(Context, CaptureByThis, 1));
}
}
};

if (!MD->getIdentifier()) {
static const llvm::StringSet<> MapLikeContainer{
"map",
"multimap",
"unordered_map",
"unordered_multimap",
};
// Infer for the map's operator []:
// std::map<string_view, ...> m;
// m[ReturnString(..)] = ...; // !dangling references in m.
if (MD->getOverloadedOperator() == OO_Subscript &&
MapLikeContainer.contains(MD->getParent()->getName()))
Annotate(MD);
return;
// FIXME: Infer for operator[] for map-like containers. For example:
// std::map<string_view, ...> m;
// m[ReturnString(..)] = ...;
}
static const llvm::StringSet<> CapturingMethods{"insert", "push",
"push_front", "push_back"};
if (!CapturingMethods.contains(MD->getName()))
return;
// Do not infer if any parameter is explicitly annotated.
for (ParmVarDecl *PVD : MD->parameters())
if (PVD->hasAttr<LifetimeCaptureByAttr>())
return;
for (ParmVarDecl *PVD : MD->parameters()) {
// Methods in standard containers that capture values typically accept
// reference-type parameters, e.g., `void push_back(const T& value)`.
// We only apply the lifetime_capture_by attribute to parameters of
// pointer-like reference types (`const T&`, `T&&`).
if (PVD->getType()->isReferenceType() &&
sema::isPointerLikeType(PVD->getType().getNonReferenceType())) {
int CaptureByThis[] = {LifetimeCaptureByAttr::THIS};
PVD->addAttr(
LifetimeCaptureByAttr::CreateImplicit(Context, CaptureByThis, 1));
}
}
Annotate(MD);
}

void Sema::inferNullableClassAttribute(CXXRecordDecl *CRD) {
Expand Down
21 changes: 18 additions & 3 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15519,10 +15519,25 @@ LambdaScopeInfo *Sema::RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator) {
LSI->CallOperator = CallOperator;
LSI->Lambda = LambdaClass;
LSI->ReturnType = CallOperator->getReturnType();
// This function in calls in situation where the context of the call operator
// is not entered, so we set AfterParameterList to false, so that
// When this function is called in situation where the context of the call
// operator is not entered, we set AfterParameterList to false, so that
// `tryCaptureVariable` finds explicit captures in the appropriate context.
LSI->AfterParameterList = false;
// There is also at least a situation as in FinishTemplateArgumentDeduction(),
// where we would set the CurContext to the lambda operator before
// substituting into it. In this case the flag needs to be true such that
// tryCaptureVariable can correctly handle potential captures thereof.
LSI->AfterParameterList = CurContext == CallOperator;

// GLTemplateParameterList is necessary for getCurGenericLambda() which is
// used at the point of dealing with potential captures.
//
// We don't use LambdaClass->isGenericLambda() because this value doesn't
// flip for instantiated generic lambdas, where no FunctionTemplateDecls are
// associated. (Technically, we could recover that list from their
// instantiation patterns, but for now, the GLTemplateParameterList seems
// unnecessary in these cases.)
if (FunctionTemplateDecl *FTD = CallOperator->getDescribedFunctionTemplate())
LSI->GLTemplateParameterList = FTD->getTemplateParameters();
const LambdaCaptureDefault LCD = LambdaClass->getLambdaCaptureDefault();

if (LCD == LCD_None)
Expand Down
40 changes: 17 additions & 23 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11451,29 +11451,23 @@ bool Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R,
bool MightInstantiateToSpecialization = false;
if (auto RetTST =
TSI->getTypeLoc().getAsAdjusted<TemplateSpecializationTypeLoc>()) {
const TemplateSpecializationType *TST = RetTST.getTypePtr();
while (TST && TST->isTypeAlias())
TST = TST->getAliasedType()->getAs<TemplateSpecializationType>();

if (TST) {
TemplateName SpecifiedName = TST->getTemplateName();
bool TemplateMatches = Context.hasSameTemplateName(
SpecifiedName, GuidedTemplate, /*IgnoreDeduced=*/true);

const QualifiedTemplateName *Qualifiers =
SpecifiedName.getAsQualifiedTemplateName();
assert(Qualifiers && "expected QualifiedTemplate");
bool SimplyWritten = !Qualifiers->hasTemplateKeyword() &&
Qualifiers->getQualifier() == nullptr;
if (SimplyWritten && TemplateMatches)
AcceptableReturnType = true;
else {
// This could still instantiate to the right type, unless we know it
// names the wrong class template.
auto *TD = SpecifiedName.getAsTemplateDecl();
MightInstantiateToSpecialization =
!(TD && isa<ClassTemplateDecl>(TD) && !TemplateMatches);
}
TemplateName SpecifiedName = RetTST.getTypePtr()->getTemplateName();
bool TemplateMatches = Context.hasSameTemplateName(
SpecifiedName, GuidedTemplate, /*IgnoreDeduced=*/true);

const QualifiedTemplateName *Qualifiers =
SpecifiedName.getAsQualifiedTemplateName();
assert(Qualifiers && "expected QualifiedTemplate");
bool SimplyWritten = !Qualifiers->hasTemplateKeyword() &&
Qualifiers->getQualifier() == nullptr;
if (SimplyWritten && TemplateMatches)
AcceptableReturnType = true;
else {
// This could still instantiate to the right type, unless we know it
// names the wrong class template.
auto *TD = SpecifiedName.getAsTemplateDecl();
MightInstantiateToSpecialization =
!(TD && isa<ClassTemplateDecl>(TD) && !TemplateMatches);
}
} else if (!RetTy.hasQualifiers() && RetTy->isDependentType()) {
MightInstantiateToSpecialization = true;
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -980,6 +980,9 @@ Sema::VarArgKind Sema::isValidVarArgType(const QualType &Ty) {
if (Ty->isObjCObjectType())
return VAK_Invalid;

if (getLangOpts().HLSL && Ty->getAs<HLSLAttributedResourceType>())
return VAK_Valid;

if (getLangOpts().MSVCCompat)
return VAK_MSVCUndefined;

Expand Down
18 changes: 17 additions & 1 deletion clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1908,7 +1908,7 @@ static bool CheckResourceHandle(
const HLSLAttributedResourceType *ResTy =
ArgType.getTypePtr()->getAs<HLSLAttributedResourceType>();
if (!ResTy) {
S->Diag(TheCall->getArg(0)->getBeginLoc(),
S->Diag(TheCall->getArg(ArgIndex)->getBeginLoc(),
diag::err_typecheck_expect_hlsl_resource)
<< ArgType;
return true;
Expand All @@ -1926,6 +1926,22 @@ static bool CheckResourceHandle(
// returning an ExprError
bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
switch (BuiltinID) {
case Builtin::BI__builtin_hlsl_resource_getpointer: {
if (SemaRef.checkArgCount(TheCall, 2) ||
CheckResourceHandle(&SemaRef, TheCall, 0) ||
CheckArgTypeMatches(&SemaRef, TheCall->getArg(1),
SemaRef.getASTContext().UnsignedIntTy))
return true;

auto *ResourceTy =
TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
QualType ContainedTy = ResourceTy->getContainedType();
// TODO: Map to an hlsl_device address space.
TheCall->setType(getASTContext().getPointerType(ContainedTy));
TheCall->setValueKind(VK_LValue);

break;
}
case Builtin::BI__builtin_hlsl_all:
case Builtin::BI__builtin_hlsl_any: {
if (SemaRef.checkArgCount(TheCall, 1))
Expand Down
Loading